Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // | ||
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) | ||
6 | // | ||
7 | // Official repository: https://github.com/boostorg/url | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP | ||
11 | #define BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP | ||
12 | |||
13 | #include <boost/url/pct_string_view.hpp> | ||
14 | #include <boost/static_assert.hpp> | ||
15 | #include <cstddef> | ||
16 | #include <iterator> | ||
17 | #include <type_traits> | ||
18 | |||
19 | namespace boost { | ||
20 | namespace urls { | ||
21 | namespace detail { | ||
22 | |||
23 | struct BOOST_SYMBOL_VISIBLE | ||
24 | any_segments_iter | ||
25 | { | ||
26 | protected: | ||
27 | explicit | ||
28 | 610 | any_segments_iter( | |
29 | core::string_view s_ = {}) noexcept | ||
30 | 610 | : s(s_) | |
31 | { | ||
32 | 610 | } | |
33 | |||
34 | 1220 | virtual ~any_segments_iter() = default; | |
35 | |||
36 | public: | ||
37 | // this is adjusted | ||
38 | // when self-intersecting | ||
39 | core::string_view s; | ||
40 | |||
41 | // the first segment, | ||
42 | // to handle special cases | ||
43 | core::string_view front; | ||
44 | |||
45 | // quick number of segments | ||
46 | // 0 = zero | ||
47 | // 1 = one | ||
48 | // 2 = two, or more | ||
49 | int fast_nseg = 0; | ||
50 | |||
51 | // whether the segments should encode colons | ||
52 | // when we measure and copy. the calling | ||
53 | // function uses this for the first | ||
54 | // segment in some cases, such as: | ||
55 | // "x:y:z" -> remove_scheme -> "y%3Az" | ||
56 | // as "y:z" would no longer represent a path | ||
57 | bool encode_colons = false; | ||
58 | |||
59 | // Rewind the iterator to the beginning | ||
60 | virtual void rewind() noexcept = 0; | ||
61 | |||
62 | // Measure and increment the current | ||
63 | // element. n is increased by the | ||
64 | // encoded size. Returns false on | ||
65 | // end of range. | ||
66 | virtual bool measure(std::size_t& n) = 0; | ||
67 | |||
68 | // Copy and increment the current | ||
69 | // element, encoding as needed. | ||
70 | virtual void copy(char*& dest, | ||
71 | char const* end) noexcept = 0; | ||
72 | }; | ||
73 | |||
74 | //------------------------------------------------ | ||
75 | // | ||
76 | // segment_iter | ||
77 | // | ||
78 | //------------------------------------------------ | ||
79 | |||
80 | // A 1-segment range | ||
81 | // allowing self-intersection | ||
82 | struct BOOST_SYMBOL_VISIBLE | ||
83 | segment_iter | ||
84 | : any_segments_iter | ||
85 | { | ||
86 | 148 | virtual ~segment_iter() = default; | |
87 | |||
88 | explicit | ||
89 | segment_iter( | ||
90 | core::string_view s) noexcept; | ||
91 | |||
92 | private: | ||
93 | bool at_end_ = false; | ||
94 | void rewind() noexcept override; | ||
95 | bool measure(std::size_t&) noexcept override; | ||
96 | void copy(char*&, char const*) noexcept override; | ||
97 | }; | ||
98 | |||
99 | //------------------------------------------------ | ||
100 | // | ||
101 | // segments_iter | ||
102 | // | ||
103 | //------------------------------------------------ | ||
104 | |||
105 | struct segments_iter_base | ||
106 | { | ||
107 | protected: | ||
108 | BOOST_URL_DECL static void | ||
109 | measure_impl(std::size_t&, | ||
110 | core::string_view, bool) noexcept; | ||
111 | BOOST_URL_DECL static void | ||
112 | copy_impl(char*&, char const*, | ||
113 | core::string_view, bool) noexcept; | ||
114 | }; | ||
115 | |||
116 | // iterates segments in a | ||
117 | // plain segment range | ||
118 | template<class FwdIt> | ||
119 | struct segments_iter | ||
120 | : any_segments_iter | ||
121 | , segments_iter_base | ||
122 | { | ||
123 | BOOST_STATIC_ASSERT( | ||
124 | std::is_convertible< | ||
125 | typename std::iterator_traits< | ||
126 | FwdIt>::reference, | ||
127 | core::string_view>::value); | ||
128 | |||
129 | 129 | segments_iter( | |
130 | FwdIt first, | ||
131 | FwdIt last) noexcept | ||
132 | 129 | : it_(first) | |
133 | 129 | , it0_(first) | |
134 | 129 | , end_(last) | |
135 | { | ||
136 |
2/3✓ Branch 0 taken 77 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
129 | if(first != last) |
137 | { | ||
138 | 129 | front = *first; | |
139 | 129 | auto it = first; | |
140 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
129 | if(++it == last) |
141 | 16 | fast_nseg = 1; | |
142 | else | ||
143 | 113 | fast_nseg = 2; | |
144 | } | ||
145 | else | ||
146 | { | ||
147 | ✗ | fast_nseg = 0; | |
148 | } | ||
149 | 129 | } | |
150 | |||
151 | private: | ||
152 | FwdIt it_; | ||
153 | FwdIt it0_; | ||
154 | FwdIt end_; | ||
155 | |||
156 | void | ||
157 | 129 | rewind() noexcept override | |
158 | { | ||
159 | 129 | it_ = it0_; | |
160 | 129 | } | |
161 | |||
162 | bool | ||
163 | 433 | measure( | |
164 | std::size_t& n) noexcept override | ||
165 | { | ||
166 |
3/3✓ Branch 0 taken 77 times.
✓ Branch 1 taken 184 times.
✓ Branch 2 taken 6 times.
|
433 | if(it_ == end_) |
167 | 129 | return false; | |
168 | 304 | measure_impl(n, | |
169 | 292 | detail::to_sv(*it_), | |
170 | 304 | encode_colons); | |
171 | 304 | ++it_; | |
172 | 304 | return true; | |
173 | } | ||
174 | |||
175 | void | ||
176 | 304 | copy( | |
177 | char*& dest, | ||
178 | char const* end) noexcept override | ||
179 | { | ||
180 | 304 | copy_impl(dest, end, | |
181 | 316 | detail::to_sv(*it_++), | |
182 | 304 | encode_colons); | |
183 | 304 | } | |
184 | }; | ||
185 | |||
186 | //------------------------------------------------ | ||
187 | // | ||
188 | // segment_encoded_iter | ||
189 | // | ||
190 | //------------------------------------------------ | ||
191 | |||
192 | // A 1-segment range | ||
193 | // allowing self-intersection | ||
194 | struct BOOST_SYMBOL_VISIBLE | ||
195 | segment_encoded_iter | ||
196 | : any_segments_iter | ||
197 | { | ||
198 | 144 | virtual ~segment_encoded_iter() = default; | |
199 | |||
200 | explicit | ||
201 | segment_encoded_iter( | ||
202 | pct_string_view const& s) noexcept; | ||
203 | |||
204 | private: | ||
205 | bool at_end_ = false; | ||
206 | void rewind() noexcept override; | ||
207 | bool measure(std::size_t&) noexcept override; | ||
208 | void copy(char*&, char const*) noexcept override; | ||
209 | }; | ||
210 | |||
211 | //------------------------------------------------ | ||
212 | // | ||
213 | // segments_encoded_iter | ||
214 | // | ||
215 | //------------------------------------------------ | ||
216 | |||
217 | // Validating and copying from | ||
218 | // a string of encoded segments | ||
219 | struct segments_encoded_iter_base | ||
220 | { | ||
221 | protected: | ||
222 | BOOST_URL_DECL static void | ||
223 | measure_impl(std::size_t&, | ||
224 | core::string_view, bool) noexcept; | ||
225 | BOOST_URL_DECL static void | ||
226 | copy_impl(char*&, char const*, | ||
227 | core::string_view, bool) noexcept; | ||
228 | }; | ||
229 | |||
230 | // iterates segments in an | ||
231 | // encoded segment range | ||
232 | template<class FwdIt> | ||
233 | struct segments_encoded_iter | ||
234 | : public any_segments_iter | ||
235 | , public segments_encoded_iter_base | ||
236 | { | ||
237 | BOOST_STATIC_ASSERT( | ||
238 | std::is_convertible< | ||
239 | typename std::iterator_traits< | ||
240 | FwdIt>::reference, | ||
241 | core::string_view>::value); | ||
242 | |||
243 | 415 | segments_encoded_iter( | |
244 | FwdIt first, | ||
245 | FwdIt last) | ||
246 | 415 | : it_(first) | |
247 | 415 | , it0_(first) | |
248 | 415 | , end_(last) | |
249 | { | ||
250 |
2/3✓ Branch 0 taken 71 times.
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
415 | if(it_ != end_) |
251 | { | ||
252 | // throw on invalid input | ||
253 |
2/2✓ Branch 2 taken 183 times.
✓ Branch 3 taken 13 times.
|
226 | front = pct_string_view( |
254 | 125 | detail::to_sv(*first)); | |
255 | 213 | auto it = first; | |
256 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 60 times.
|
213 | if(++it == last) |
257 | 65 | fast_nseg = 1; | |
258 | else | ||
259 | 148 | fast_nseg = 2; | |
260 | } | ||
261 | else | ||
262 | { | ||
263 | 189 | fast_nseg = 0; | |
264 | } | ||
265 | 415 | } | |
266 | |||
267 | private: | ||
268 | FwdIt it_; | ||
269 | FwdIt it0_; | ||
270 | FwdIt end_; | ||
271 | |||
272 | void | ||
273 | 400 | rewind() noexcept override | |
274 | { | ||
275 | 400 | it_ = it0_; | |
276 | 400 | } | |
277 | |||
278 | bool | ||
279 | 876 | measure( | |
280 | std::size_t& n) override | ||
281 | { | ||
282 |
3/3✓ Branch 0 taken 245 times.
✓ Branch 1 taken 268 times.
✓ Branch 2 taken 258 times.
|
876 | if(it_ == end_) |
283 | 400 | return false; | |
284 | // throw on invalid input | ||
285 | 474 | measure_impl(n, | |
286 |
1/2✓ Branch 2 taken 258 times.
✗ Branch 3 not taken.
|
476 | pct_string_view( |
287 | 476 | detail::to_sv(*it_++)), | |
288 | 476 | encode_colons); | |
289 | 474 | return true; | |
290 | } | ||
291 | |||
292 | void | ||
293 | 472 | copy( | |
294 | char*& dest, | ||
295 | char const* end) noexcept override | ||
296 | { | ||
297 | 472 | copy_impl(dest, end, | |
298 | 472 | detail::to_sv(*it_++), | |
299 | 472 | encode_colons); | |
300 | 472 | } | |
301 | }; | ||
302 | |||
303 | //------------------------------------------------ | ||
304 | |||
305 | template<class FwdIt> | ||
306 | segments_iter<FwdIt> | ||
307 | 129 | make_segments_iter( | |
308 | FwdIt first, FwdIt last) | ||
309 | { | ||
310 | return segments_iter< | ||
311 | 129 | FwdIt>(first, last); | |
312 | } | ||
313 | |||
314 | template<class FwdIt> | ||
315 | segments_encoded_iter<FwdIt> | ||
316 | 385 | make_segments_encoded_iter( | |
317 | FwdIt first, FwdIt last) | ||
318 | { | ||
319 | return segments_encoded_iter< | ||
320 | 385 | FwdIt>(first, last); | |
321 | } | ||
322 | |||
323 | } // detail | ||
324 | } // urls | ||
325 | } // boost | ||
326 | |||
327 | #endif | ||
328 |