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   9364 segments_iter_impl:: 24   9364 segments_iter_impl::
25   segments_iter_impl( 25   segments_iter_impl(
HITCBC 26   9364 detail::path_ref const& ref_) noexcept 26   9364 detail::path_ref const& ref_) noexcept
HITCBC 27   9364 : ref(ref_) 27   9364 : ref(ref_)
28   { 28   {
HITCBC 29   9364 pos = path_prefix(ref.buffer()); 29   9364 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   9364 decoded_prefix = pos; 31   9364 decoded_prefix = pos;
HITCBC 32   9364 update(); 32   9364 update();
HITCBC 33   9364 } 33   9364 }
34   34  
35   // end 35   // end
36   inline 36   inline
HITCBC 37   16416 segments_iter_impl:: 37   16416 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   16416 int) noexcept 40   16416 int) noexcept
HITCBC 41   16416 : ref(ref_) 41   16416 : ref(ref_)
HITCBC 42   16416 , pos(ref.size()) 42   16416 , pos(ref.size())
HITCBC 43   16416 , next(ref.size()) 43   16416 , next(ref.size())
HITCBC 44   16416 , index(ref.nseg()) 44   16416 , 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   16416 decoded_prefix = ref.decoded_size(); 47   16416 decoded_prefix = ref.decoded_size();
HITCBC 48   16416 } 48   16416 }
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   12695 segments_iter_impl:: 99   12695 segments_iter_impl::
100   update() noexcept 100   update() noexcept
101   { 101   {
HITCBC 102   12695 BOOST_ASSERT( 102   12695 BOOST_ASSERT(
103   pos == 0 || 103   pos == 0 ||
104   ref.data()[pos - 1] == '/'); 104   ref.data()[pos - 1] == '/');
HITCBC 105   12695 auto const end = ref.end(); 105   12695 auto const end = ref.end();
106   char const* const p0 = 106   char const* const p0 =
HITCBC 107   12695 ref.data() + pos; 107   12695 ref.data() + pos;
HITCBC 108   12695 dn = 0; 108   12695 dn = 0;
HITCBC 109   12695 auto p = p0; 109   12695 auto p = p0;
HITCBC 110   56663 while(p != end) 110   56663 while(p != end)
111   { 111   {
HITCBC 112   49262 if(*p == '/') 112   49262 if(*p == '/')
HITCBC 113   5294 break; 113   5294 break;
HITCBC 114   43968 if(*p != '%') 114   43968 if(*p != '%')
115   { 115   {
HITCBC 116   39695 ++p; 116   39695 ++p;
HITCBC 117   39695 continue; 117   39695 continue;
118   } 118   }
HITCBC 119   4273 p += 3; 119   4273 p += 3;
HITCBC 120   4273 dn += 2; 120   4273 dn += 2;
121   } 121   }
HITCBC 122   12695 next = p - ref.data(); 122   12695 next = p - ref.data();
HITCBC 123   12695 dn = p - p0 - dn; 123   12695 dn = p - p0 - dn;
HITCBC 124   12695 s_ = make_pct_string_view_unsafe( 124   12695 s_ = make_pct_string_view_unsafe(
HITCBC 125   12695 p0, p - p0, dn); 125   12695 p0, p - p0, dn);
HITCBC 126   12695 } 126   12695 }
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   1979 segments_iter_impl:: 174   1979 segments_iter_impl::
175   decrement() noexcept 175   decrement() noexcept
176   { 176   {
HITCBC 177   1979 BOOST_ASSERT(index != 0); 177   1979 BOOST_ASSERT(index != 0);
HITCBC 178   1979 auto const current_dn = dn; 178   1979 auto const current_dn = dn;
HITCBC 179   1979 auto const current_index = index; 179   1979 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   1979 decoded_prefix -= current_dn; 181   1979 decoded_prefix -= current_dn;
HITCBC 182   1979 if(current_index > 0 && decoded_prefix > 0) 182   1979 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   1979 --decoded_prefix; 184   1979 --decoded_prefix;
HITCBC 185   1979 --index; 185   1979 --index;
HITCBC 186   1979 if(index == 0) 186   1979 if(index == 0)
187   { 187   {
HITCBC 188   794 pos = path_prefix(ref.buffer()); 188   794 pos = path_prefix(ref.buffer());
HITCBC 189   794 decoded_prefix = pos; 189   794 decoded_prefix = pos;
HITCBC 190   794 update(); 190   794 update();
HITCBC 191   794 BOOST_ASSERT(! s_.ends_with('/')); 191   794 BOOST_ASSERT(! s_.ends_with('/'));
HITCBC 192   794 return; 192   794 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   1185 auto const begin = ref.data() + 196   1185 auto const begin = ref.data() +
HITCBC 197   1185 path_prefix(ref.buffer()); 197   1185 path_prefix(ref.buffer());
HITCBC 198   1185 auto p = ref.data() + pos; 198   1185 auto p = ref.data() + pos;
HITCBC 199   1185 BOOST_ASSERT(p != begin); 199   1185 BOOST_ASSERT(p != begin);
HITCBC 200   4738 while(p != begin) 200   4738 while(p != begin)
201   { 201   {
HITCBC 202   4738 --p; 202   4738 --p;
HITCBC 203   4738 if(*p == '/') 203   4738 if(*p == '/')
HITCBC 204   1185 break; 204   1185 break;
205   } 205   }
HITCBC 206   1185 pos = p - ref.data() + 1; 206   1185 pos = p - ref.data() + 1;
HITCBC 207   1185 update(); 207   1185 update();
HITCBC 208   1185 --pos; 208   1185 --pos;
209   } 209   }
210   210  
211   } // detail 211   } // detail
212   } // urls 212   } // urls
213   } // boost 213   } // boost
214   214  
215   #endif 215   #endif