include/boost/url/detail/impl/segments_iter_impl.hpp

99.2% Lines (123/124) 100.0% Functions (6/6) 76.0% Branches (38/50)
include/boost/url/detail/impl/segments_iter_impl.hpp
Line Branch Hits 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
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 438 times.
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
2/2
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 199 times.
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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 199 times.
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
1/2
✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
199 if(pos != ref.size())
85 {
86
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 199 times.
199 BOOST_ASSERT(
87 ref.data()[pos] == '/');
88 199 ++pos; // skip '/'
89 199 update();
90 199 --pos;
91 199 return;
92 }
93
94 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
2/2
✓ Branch 0 taken 9508 times.
✓ Branch 1 taken 1136 times.
10644 while(p != end)
108 {
109
2/2
✓ Branch 0 taken 1624 times.
✓ Branch 1 taken 7884 times.
9508 if(*p == '/')
110 1624 break;
111
2/2
✓ Branch 0 taken 7516 times.
✓ Branch 1 taken 368 times.
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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2862 times.
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
2/2
✓ Branch 0 taken 1634 times.
✓ Branch 1 taken 1228 times.
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
2/2
✓ Branch 1 taken 1162 times.
✓ Branch 2 taken 1700 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1700 times.
1700 BOOST_ASSERT(p != end);
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1700 times.
1700 BOOST_ASSERT(*p == '/');
148 1700 dn = 0;
149 1700 ++p; // skip '/'
150 1700 auto const p0 = p;
151
2/2
✓ Branch 0 taken 6811 times.
✓ Branch 1 taken 724 times.
7535 while(p != end)
152 {
153
2/2
✓ Branch 0 taken 976 times.
✓ Branch 1 taken 5835 times.
6811 if(*p == '/')
154 976 break;
155
2/2
✓ Branch 0 taken 5707 times.
✓ Branch 1 taken 128 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1584 times.
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
2/4
✓ Branch 0 taken 1584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1584 times.
✗ Branch 3 not taken.
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
2/2
✓ Branch 0 taken 549 times.
✓ Branch 1 taken 1035 times.
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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 549 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1035 times.
1035 BOOST_ASSERT(p != begin);
200 1035 dn = 0;
201
1/2
✓ Branch 0 taken 3188 times.
✗ Branch 1 not taken.
3188 while(p != begin)
202 {
203 3188 --p;
204
2/2
✓ Branch 0 taken 1035 times.
✓ Branch 1 taken 2153 times.
3188 if(*p == '/')
205 {
206 1035 ++dn;
207 1035 break;
208 }
209
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 2125 times.
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
225