Line data Source code
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 610 : 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 74 : 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 79 : segments_iter(
130 : FwdIt first,
131 : FwdIt last) noexcept
132 79 : : it_(first)
133 79 : , it0_(first)
134 79 : , end_(last)
135 : {
136 79 : if(first != last)
137 : {
138 79 : front = *first;
139 79 : auto it = first;
140 79 : if(++it == last)
141 8 : fast_nseg = 1;
142 : else
143 71 : fast_nseg = 2;
144 : }
145 : else
146 : {
147 0 : fast_nseg = 0;
148 : }
149 79 : }
150 :
151 : private:
152 : FwdIt it_;
153 : FwdIt it0_;
154 : FwdIt end_;
155 :
156 : void
157 79 : rewind() noexcept override
158 : {
159 79 : it_ = it0_;
160 79 : }
161 :
162 : bool
163 267 : measure(
164 : std::size_t& n) noexcept override
165 : {
166 267 : if(it_ == end_)
167 79 : return false;
168 188 : measure_impl(n,
169 182 : detail::to_sv(*it_),
170 188 : encode_colons);
171 188 : ++it_;
172 188 : return true;
173 : }
174 :
175 : void
176 188 : copy(
177 : char*& dest,
178 : char const* end) noexcept override
179 : {
180 188 : copy_impl(dest, end,
181 194 : detail::to_sv(*it_++),
182 188 : encode_colons);
183 188 : }
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 72 : 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 385 : segments_encoded_iter(
244 : FwdIt first,
245 : FwdIt last)
246 385 : : it_(first)
247 385 : , it0_(first)
248 385 : , end_(last)
249 : {
250 385 : if(it_ != end_)
251 : {
252 : // throw on invalid input
253 196 : front = pct_string_view(
254 125 : detail::to_sv(*first));
255 183 : auto it = first;
256 183 : if(++it == last)
257 65 : fast_nseg = 1;
258 : else
259 118 : fast_nseg = 2;
260 : }
261 : else
262 : {
263 189 : fast_nseg = 0;
264 : }
265 385 : }
266 :
267 : private:
268 : FwdIt it_;
269 : FwdIt it0_;
270 : FwdIt end_;
271 :
272 : void
273 370 : rewind() noexcept override
274 : {
275 370 : it_ = it0_;
276 370 : }
277 :
278 : bool
279 771 : measure(
280 : std::size_t& n) override
281 : {
282 771 : if(it_ == end_)
283 370 : return false;
284 : // throw on invalid input
285 399 : measure_impl(n,
286 401 : pct_string_view(
287 401 : detail::to_sv(*it_++)),
288 401 : encode_colons);
289 399 : return true;
290 : }
291 :
292 : void
293 397 : copy(
294 : char*& dest,
295 : char const* end) noexcept override
296 : {
297 397 : copy_impl(dest, end,
298 397 : detail::to_sv(*it_++),
299 397 : encode_colons);
300 397 : }
301 : };
302 :
303 : //------------------------------------------------
304 :
305 : template<class FwdIt>
306 : segments_iter<FwdIt>
307 79 : make_segments_iter(
308 : FwdIt first, FwdIt last)
309 : {
310 : return segments_iter<
311 79 : 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
|