99.13% Lines (114/115) 100.00% Functions (6/6)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) 3   // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/boostorg/url 8   // Official repository: https://github.com/boostorg/url
9   // 9   //
10   10  
11   #ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP 11   #ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP
12   #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP 12   #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP
13   13  
14   #include <boost/url/detail/decode.hpp> 14   #include <boost/url/detail/decode.hpp>
15   #include <boost/url/detail/path.hpp> 15   #include <boost/url/detail/path.hpp>
16   #include <boost/assert.hpp> 16   #include <boost/assert.hpp>
17   17  
18   namespace boost { 18   namespace boost {
19   namespace urls { 19   namespace urls {
20   namespace detail { 20   namespace detail {
21   21  
22   // begin 22   // begin
23   inline 23   inline
HITCBC 24   9995 segments_iter_impl:: 24   10055 segments_iter_impl::
25   segments_iter_impl( 25   segments_iter_impl(
HITCBC 26   9995 detail::path_ref const& ref_) noexcept 26   10055 detail::path_ref const& ref_) noexcept
HITCBC 27   9995 : ref(ref_) 27   10055 : ref(ref_)
28   { 28   {
HITCBC 29   9995 pos = path_prefix(ref.buffer()); 29   10055 pos = path_prefix(ref.buffer());
30   // begin() starts after any malleable prefix but remembers decoded chars skipped 30   // begin() starts after any malleable prefix but remembers decoded chars skipped
HITCBC 31   9995 decoded_prefix = pos; 31   10055 decoded_prefix = pos;
HITCBC 32   9995 update(); 32   10055 update();
HITCBC 33   9995 } 33   10055 }
34   34  
35   // end 35   // end
36   inline 36   inline
HITCBC 37   17510 segments_iter_impl:: 37   17570 segments_iter_impl::
38   segments_iter_impl( 38   segments_iter_impl(
39   detail::path_ref const& ref_, 39   detail::path_ref const& ref_,
HITCBC 40   17510 int) noexcept 40   17570 int) noexcept
HITCBC 41   17510 : ref(ref_) 41   17570 : ref(ref_)
HITCBC 42   17510 , pos(ref.size()) 42   17570 , pos(ref.size())
HITCBC 43   17510 , next(ref.size()) 43   17570 , next(ref.size())
HITCBC 44   17510 , index(ref.nseg()) 44   17570 , index(ref.nseg())
45   { 45   {
46   // end() carries the total decoded length for O(1) range math 46   // end() carries the total decoded length for O(1) range math
HITCBC 47   17510 decoded_prefix = ref.decoded_size(); 47   17570 decoded_prefix = ref.decoded_size();
HITCBC 48   17510 } 48   17570 }
49   49  
50   inline 50   inline
HITCBC 51   2313 segments_iter_impl:: 51   2313 segments_iter_impl::
52   segments_iter_impl( 52   segments_iter_impl(
53   url_impl const& u_, 53   url_impl const& u_,
54   std::size_t pos_, 54   std::size_t pos_,
HITCBC 55   2313 std::size_t index_) noexcept 55   2313 std::size_t index_) noexcept
HITCBC 56   2313 : ref(u_) 56   2313 : ref(u_)
HITCBC 57   2313 , pos(pos_) 57   2313 , pos(pos_)
HITCBC 58   2313 , index(index_) 58   2313 , index(index_)
59   { 59   {
HITCBC 60   2313 auto const total = ref.nseg(); 60   2313 auto const total = ref.nseg();
HITCBC 61   2313 if(index >= total) 61   2313 if(index >= total)
62   { 62   {
HITCBC 63   961 pos = ref.size(); 63   961 pos = ref.size();
HITCBC 64   961 next = ref.size(); 64   961 next = ref.size();
HITCBC 65   961 decoded_prefix = ref.decoded_size(); 65   961 decoded_prefix = ref.decoded_size();
66   // iterator equal to end: nothing to decode 66   // iterator equal to end: nothing to decode
HITCBC 67   961 dn = 0; 67   961 dn = 0;
HITCBC 68   961 return; 68   961 return;
69   } 69   }
70   70  
HITCBC 71   1352 if(index == 0) 71   1352 if(index == 0)
72   { 72   {
HITCBC 73   763 pos = path_prefix(ref.buffer()); 73   763 pos = path_prefix(ref.buffer());
74   // first segment inherits the prefix size (including leading '/') 74   // first segment inherits the prefix size (including leading '/')
HITCBC 75   763 decoded_prefix = pos; 75   763 decoded_prefix = pos;
HITCBC 76   763 update(); 76   763 update();
HITCBC 77   763 return; 77   763 return;
78   } 78   }
79   79  
HITCBC 80   589 BOOST_ASSERT(pos <= ref.size()); 80   589 BOOST_ASSERT(pos <= ref.size());
81   // compute decoded prefix by scanning once up to the encoded offset 81   // compute decoded prefix by scanning once up to the encoded offset
HITCBC 82   589 decoded_prefix = detail::decode_bytes_unsafe( 82   589 decoded_prefix = detail::decode_bytes_unsafe(
83   core::string_view(ref.data(), pos)); 83   core::string_view(ref.data(), pos));
HITCBC 84   589 if(pos != ref.size()) 84   589 if(pos != ref.size())
85   { 85   {
HITCBC 86   589 BOOST_ASSERT( 86   589 BOOST_ASSERT(
87   ref.data()[pos] == '/'); 87   ref.data()[pos] == '/');
HITCBC 88   589 ++pos; // skip '/' 88   589 ++pos; // skip '/'
HITCBC 89   589 update(); 89   589 update();
HITCBC 90   589 --pos; 90   589 --pos;
HITCBC 91   589 return; 91   589 return;
92   } 92   }
93   93  
MISUBC 94   ✗ update(); 94   ✗ update();
95   } 95   }
96   96  
97   inline 97   inline
98   void 98   void
HITCBC 99   16379 segments_iter_impl:: 99   16487 segments_iter_impl::
100   update() noexcept 100   update() noexcept
101   { 101   {
HITCBC 102   16379 BOOST_ASSERT( 102   16487 BOOST_ASSERT(
103   pos == 0 || 103   pos == 0 ||
104   ref.data()[pos - 1] == '/'); 104   ref.data()[pos - 1] == '/');
HITCBC 105   16379 auto const end = ref.end(); 105   16487 auto const end = ref.end();
106   char const* const p0 = 106   char const* const p0 =
HITCBC 107   16379 ref.data() + pos; 107   16487 ref.data() + pos;
HITCBC 108   16379 dn = 0; 108   16487 dn = 0;
HITCBC 109   16379 auto p = p0; 109   16487 auto p = p0;
HITCBC 110   66376 while(p != end) 110   66916 while(p != end)
111   { 111   {
HITCBC 112   56586 if(*p == '/') 112   57018 if(*p == '/')
HITCBC 113   6589 break; 113   6589 break;
HITCBC 114   49997 if(*p != '%') 114   50429 if(*p != '%')
115   { 115   {
HITCBC 116   45414 ++p; 116   45750 ++p;
HITCBC 117   45414 continue; 117   45750 continue;
118   } 118   }
HITCBC 119   4583 p += 3; 119   4679 p += 3;
HITCBC 120   4583 dn += 2; 120   4679 dn += 2;
121   } 121   }
HITCBC 122   16379 next = p - ref.data(); 122   16487 next = p - ref.data();
HITCBC 123   16379 dn = p - p0 - dn; 123   16487 dn = p - p0 - dn;
HITCBC 124   16379 s_ = make_pct_string_view_unsafe( 124   16487 s_ = make_pct_string_view_unsafe(
HITCBC 125   16379 p0, p - p0, dn); 125   16487 p0, p - p0, dn);
HITCBC 126   16379 } 126   16487 }
127   127  
128   inline 128   inline
129   void 129   void
HITCBC 130   10857 segments_iter_impl:: 130   10857 segments_iter_impl::
131   increment() noexcept 131   increment() noexcept
132   { 132   {
HITCBC 133   10857 BOOST_ASSERT( 133   10857 BOOST_ASSERT(
134   index != ref.nseg()); 134   index != ref.nseg());
HITCBC 135   10857 auto const old_index = index; 135   10857 auto const old_index = index;
HITCBC 136   10857 auto const old_dn = dn; 136   10857 auto const old_dn = dn;
137   // add decoded length of previous segment 137   // add decoded length of previous segment
HITCBC 138   10857 decoded_prefix += old_dn; 138   10857 decoded_prefix += old_dn;
HITCBC 139   10857 if(old_index > 0) 139   10857 if(old_index > 0)
140   // account for the '/' separator we just crossed 140   // account for the '/' separator we just crossed
HITCBC 141   6005 ++decoded_prefix; 141   6005 ++decoded_prefix;
HITCBC 142   10857 ++index; 142   10857 ++index;
HITCBC 143   10857 pos = next; 143   10857 pos = next;
HITCBC 144   10857 if(index == ref.nseg()) 144   10857 if(index == ref.nseg())
HITCBC 145   4765 return; 145   4765 return;
146   // "/" segment 146   // "/" segment
HITCBC 147   6092 auto const end = ref.end(); 147   6092 auto const end = ref.end();
HITCBC 148   6092 auto p = ref.data() + pos; 148   6092 auto p = ref.data() + pos;
HITCBC 149   6092 BOOST_ASSERT(p != end); 149   6092 BOOST_ASSERT(p != end);
HITCBC 150   6092 BOOST_ASSERT(*p == '/'); 150   6092 BOOST_ASSERT(*p == '/');
HITCBC 151   6092 dn = 0; 151   6092 dn = 0;
HITCBC 152   6092 ++p; // skip '/' 152   6092 ++p; // skip '/'
HITCBC 153   6092 auto const p0 = p; 153   6092 auto const p0 = p;
HITCBC 154   31779 while(p != end) 154   31779 while(p != end)
155   { 155   {
HITCBC 156   28672 if(*p == '/') 156   28672 if(*p == '/')
HITCBC 157   2985 break; 157   2985 break;
HITCBC 158   25687 if(*p != '%') 158   25687 if(*p != '%')
159   { 159   {
HITCBC 160   24649 ++p; 160   24649 ++p;
HITCBC 161   24649 continue; 161   24649 continue;
162   } 162   }
HITCBC 163   1038 p += 3; 163   1038 p += 3;
HITCBC 164   1038 dn += 2; 164   1038 dn += 2;
165   } 165   }
HITCBC 166   6092 next = p - ref.data(); 166   6092 next = p - ref.data();
HITCBC 167   6092 dn = p - p0 - dn; 167   6092 dn = p - p0 - dn;
HITCBC 168   6092 s_ = make_pct_string_view_unsafe( 168   6092 s_ = make_pct_string_view_unsafe(
HITCBC 169   6092 p0, p - p0, dn); 169   6092 p0, p - p0, dn);
170   } 170   }
171   171  
172   inline 172   inline
173   void 173   void
HITCBC 174   5032 segments_iter_impl:: 174   5080 segments_iter_impl::
175   decrement() noexcept 175   decrement() noexcept
176   { 176   {
HITCBC 177   5032 BOOST_ASSERT(index != 0); 177   5080 BOOST_ASSERT(index != 0);
HITCBC 178   5032 auto const current_dn = dn; 178   5080 auto const current_dn = dn;
HITCBC 179   5032 auto const current_index = index; 179   5080 auto const current_index = index;
180   // remove the decoded length of the segment we're leaving 180   // remove the decoded length of the segment we're leaving
HITCBC 181   5032 decoded_prefix -= current_dn; 181   5080 decoded_prefix -= current_dn;
HITCBC 182   5032 if(current_index > 0 && decoded_prefix > 0) 182   5080 if(current_index > 0 && decoded_prefix > 0)
183   // drop the '/' separator when stepping left of it 183   // drop the '/' separator when stepping left of it
HITCBC 184   5032 --decoded_prefix; 184   5080 --decoded_prefix;
HITCBC 185   5032 --index; 185   5080 --index;
HITCBC 186   5032 if(index == 0) 186   5080 if(index == 0)
187   { 187   {
HITCBC 188   2138 pos = path_prefix(ref.buffer()); 188   2186 pos = path_prefix(ref.buffer());
HITCBC 189   2138 decoded_prefix = pos; 189   2186 decoded_prefix = pos;
HITCBC 190   2138 update(); 190   2186 update();
HITCBC 191   2138 BOOST_ASSERT(! s_.ends_with('/')); 191   2186 BOOST_ASSERT(! s_.ends_with('/'));
HITCBC 192   2138 return; 192   2186 return;
193   } 193   }
194   // scan backwards to find the '/' before 194   // scan backwards to find the '/' before
195   // the previous segment 195   // the previous segment
HITCBC 196   2894 auto const begin = ref.data() + 196   2894 auto const begin = ref.data() +
HITCBC 197   2894 path_prefix(ref.buffer()); 197   2894 path_prefix(ref.buffer());
HITCBC 198   2894 auto p = ref.data() + pos; 198   2894 auto p = ref.data() + pos;
HITCBC 199   2894 BOOST_ASSERT(p != begin); 199   2894 BOOST_ASSERT(p != begin);
HITCBC 200   9221 while(p != begin) 200   9221 while(p != begin)
201   { 201   {
HITCBC 202   9221 --p; 202   9221 --p;
HITCBC 203   9221 if(*p == '/') 203   9221 if(*p == '/')
HITCBC 204   2894 break; 204   2894 break;
205   } 205   }
HITCBC 206   2894 pos = p - ref.data() + 1; 206   2894 pos = p - ref.data() + 1;
HITCBC 207   2894 update(); 207   2894 update();
HITCBC 208   2894 --pos; 208   2894 --pos;
209   } 209   }
210   210  
211   } // detail 211   } // detail
212   } // urls 212   } // urls
213   } // boost 213   } // boost
214   214  
215   #endif 215   #endif