Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2022 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_PCT_STRING_VIEW_HPP | ||
11 | #define BOOST_URL_PCT_STRING_VIEW_HPP | ||
12 | |||
13 | #include <boost/url/detail/config.hpp> | ||
14 | #include <boost/url/encoding_opts.hpp> | ||
15 | #include <boost/url/error_types.hpp> | ||
16 | #include <boost/core/detail/string_view.hpp> | ||
17 | #include <boost/url/grammar/string_token.hpp> | ||
18 | #include <boost/url/grammar/string_view_base.hpp> | ||
19 | #include <cstddef> | ||
20 | #include <iterator> | ||
21 | #include <string> | ||
22 | #include <type_traits> | ||
23 | #include <utility> | ||
24 | |||
25 | namespace boost { | ||
26 | namespace urls { | ||
27 | |||
28 | //------------------------------------------------ | ||
29 | |||
30 | #ifndef BOOST_URL_DOCS | ||
31 | class decode_view; | ||
32 | class pct_string_view; | ||
33 | |||
34 | pct_string_view | ||
35 | make_pct_string_view_unsafe( | ||
36 | char const*, std::size_t, | ||
37 | std::size_t) noexcept; | ||
38 | |||
39 | namespace detail { | ||
40 | core::string_view& | ||
41 | ref(pct_string_view& s) noexcept; | ||
42 | } // detail | ||
43 | #endif | ||
44 | |||
45 | //------------------------------------------------ | ||
46 | |||
47 | /** A reference to a valid percent-encoded string | ||
48 | |||
49 | Objects of this type behave like a | ||
50 | `core::string_view` and have the same interface, | ||
51 | but offer an additional invariant: they can | ||
52 | only be constructed from strings containing | ||
53 | valid percent-escapes. | ||
54 | |||
55 | Attempting construction from a string | ||
56 | containing invalid or malformed percent | ||
57 | escapes results in an exception. | ||
58 | |||
59 | @par Operators | ||
60 | The following operators are supported between | ||
61 | @ref pct_string_view and any object that is | ||
62 | convertible to `core::string_view` | ||
63 | |||
64 | @code | ||
65 | bool operator==( pct_string_view, pct_string_view ) noexcept; | ||
66 | bool operator!=( pct_string_view, pct_string_view ) noexcept; | ||
67 | bool operator<=( pct_string_view, pct_string_view ) noexcept; | ||
68 | bool operator< ( pct_string_view, pct_string_view ) noexcept; | ||
69 | bool operator> ( pct_string_view, pct_string_view ) noexcept; | ||
70 | bool operator>=( pct_string_view, pct_string_view ) noexcept; | ||
71 | @endcode | ||
72 | */ | ||
73 | class pct_string_view final | ||
74 | : public grammar::string_view_base | ||
75 | { | ||
76 | std::size_t dn_ = 0; | ||
77 | |||
78 | #ifndef BOOST_URL_DOCS | ||
79 | friend | ||
80 | pct_string_view | ||
81 | make_pct_string_view_unsafe( | ||
82 | char const*, std::size_t, | ||
83 | std::size_t) noexcept; | ||
84 | |||
85 | friend | ||
86 | core::string_view& | ||
87 | detail::ref(pct_string_view&) noexcept; | ||
88 | #endif | ||
89 | |||
90 | // unsafe | ||
91 | 33744 | pct_string_view( | |
92 | char const* data, | ||
93 | std::size_t size, | ||
94 | std::size_t dn) noexcept | ||
95 | 33744 | : string_view_base(data, size) | |
96 | 33744 | , dn_(dn) | |
97 | { | ||
98 | 33744 | } | |
99 | |||
100 | BOOST_URL_DECL | ||
101 | void | ||
102 | decode_impl( | ||
103 | string_token::arg& dest, | ||
104 | encoding_opts opt) const; | ||
105 | |||
106 | public: | ||
107 | /** Constructor | ||
108 | |||
109 | Default constructed string are empty. | ||
110 | |||
111 | @par Complexity | ||
112 | Constant. | ||
113 | |||
114 | @par Exception Safety | ||
115 | Throws nothing. | ||
116 | */ | ||
117 | 16229 | constexpr pct_string_view() = default; | |
118 | |||
119 | /** Constructor | ||
120 | |||
121 | The copy references the same | ||
122 | underlying character buffer. | ||
123 | Ownership is not transferred. | ||
124 | |||
125 | @par Postconditions | ||
126 | @code | ||
127 | this->data() == other.data() | ||
128 | @endcode | ||
129 | |||
130 | @par Complexity | ||
131 | Constant. | ||
132 | |||
133 | @par Exception Safety | ||
134 | Throws nothing. | ||
135 | |||
136 | @par other The string to copy. | ||
137 | */ | ||
138 | constexpr | ||
139 | pct_string_view( | ||
140 | pct_string_view const& other) = default; | ||
141 | |||
142 | /** Constructor | ||
143 | |||
144 | The newly constructed string references | ||
145 | the specified character buffer. | ||
146 | Ownership is not transferred. | ||
147 | |||
148 | @par Postconditions | ||
149 | @code | ||
150 | this->data() == core::string_view(s).data() | ||
151 | @endcode | ||
152 | |||
153 | @par Complexity | ||
154 | Linear in `core::string_view(s).size()`. | ||
155 | |||
156 | @par Exception Safety | ||
157 | Exceptions thrown on invalid input. | ||
158 | |||
159 | @throw system_error | ||
160 | The string contains an invalid percent encoding. | ||
161 | |||
162 | @tparam String A type convertible to `core::string_view` | ||
163 | |||
164 | @param s The string to construct from. | ||
165 | */ | ||
166 | template< | ||
167 | class String | ||
168 | #ifndef BOOST_URL_DOCS | ||
169 | , class = typename std::enable_if< | ||
170 | std::is_convertible< | ||
171 | String, | ||
172 | core::string_view | ||
173 | >::value>::type | ||
174 | #endif | ||
175 | > | ||
176 | 1862 | pct_string_view( | |
177 | String const& s) | ||
178 | : pct_string_view( | ||
179 | 1862 | detail::to_sv(s)) | |
180 | { | ||
181 | 1752 | } | |
182 | |||
183 | /** Constructor (deleted) | ||
184 | */ | ||
185 | pct_string_view( | ||
186 | std::nullptr_t) = delete; | ||
187 | |||
188 | /** Constructor | ||
189 | |||
190 | The newly constructed string references | ||
191 | the specified character buffer. Ownership | ||
192 | is not transferred. | ||
193 | |||
194 | @par Postconditions | ||
195 | @code | ||
196 | this->data() == s && this->size() == len | ||
197 | @endcode | ||
198 | |||
199 | @par Complexity | ||
200 | Linear in `len`. | ||
201 | |||
202 | @par Exception Safety | ||
203 | Exceptions thrown on invalid input. | ||
204 | |||
205 | @throw system_error | ||
206 | The string contains an invalid percent encoding. | ||
207 | |||
208 | @param s, len The string to construct from. | ||
209 | */ | ||
210 | 182 | pct_string_view( | |
211 | char const* s, | ||
212 | std::size_t len) | ||
213 | 182 | : pct_string_view( | |
214 |
1/2✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
|
182 | core::string_view(s, len)) |
215 | { | ||
216 | 182 | } | |
217 | |||
218 | /** Constructor | ||
219 | |||
220 | The newly constructed string references | ||
221 | the specified character buffer. Ownership | ||
222 | is not transferred. | ||
223 | |||
224 | @par Postconditions | ||
225 | @code | ||
226 | this->data() == s.data() && this->size() == s.size() | ||
227 | @endcode | ||
228 | |||
229 | @par Complexity | ||
230 | Linear in `s.size()`. | ||
231 | |||
232 | @par Exception Safety | ||
233 | Exceptions thrown on invalid input. | ||
234 | |||
235 | @throw system_error | ||
236 | The string contains an invalid percent encoding. | ||
237 | |||
238 | @param s The string to construct from. | ||
239 | */ | ||
240 | BOOST_URL_DECL | ||
241 | pct_string_view( | ||
242 | core::string_view s); | ||
243 | |||
244 | /** Assignment | ||
245 | |||
246 | The copy references the same | ||
247 | underlying character buffer. | ||
248 | Ownership is not transferred. | ||
249 | |||
250 | @par Postconditions | ||
251 | @code | ||
252 | this->data() == other.data() | ||
253 | @endcode | ||
254 | |||
255 | @par Complexity | ||
256 | Constant. | ||
257 | |||
258 | @par Exception Safety | ||
259 | Throws nothing. | ||
260 | |||
261 | @par other The string to copy. | ||
262 | */ | ||
263 | pct_string_view& operator=( | ||
264 | pct_string_view const& other) = default; | ||
265 | |||
266 | friend | ||
267 | BOOST_URL_DECL | ||
268 | system::result<pct_string_view> | ||
269 | make_pct_string_view( | ||
270 | core::string_view s) noexcept; | ||
271 | |||
272 | //-------------------------------------------- | ||
273 | |||
274 | /** Return the decoded size | ||
275 | |||
276 | This function returns the number of | ||
277 | characters in the resulting string if | ||
278 | percent escapes were converted into | ||
279 | ordinary characters. | ||
280 | |||
281 | @par Complexity | ||
282 | Constant. | ||
283 | |||
284 | @par Exception Safety | ||
285 | Throws nothing. | ||
286 | */ | ||
287 | std::size_t | ||
288 | 14500 | decoded_size() const noexcept | |
289 | { | ||
290 | 14500 | return dn_; | |
291 | } | ||
292 | |||
293 | /** Return the string as a range of decoded characters | ||
294 | |||
295 | @par Complexity | ||
296 | Constant. | ||
297 | |||
298 | @par Exception Safety | ||
299 | Throws nothing. | ||
300 | |||
301 | @see | ||
302 | @ref decode_view. | ||
303 | */ | ||
304 | decode_view | ||
305 | operator*() const noexcept; | ||
306 | |||
307 | /** Return the string with percent-decoding | ||
308 | |||
309 | This function converts percent escapes | ||
310 | in the string into ordinary characters | ||
311 | and returns the result. | ||
312 | When called with no arguments, the | ||
313 | return type is `std::string`. | ||
314 | Otherwise, the return type and style | ||
315 | of output is determined by which string | ||
316 | token is passed. | ||
317 | |||
318 | @par Example | ||
319 | @code | ||
320 | assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" ); | ||
321 | @endcode | ||
322 | |||
323 | @par Complexity | ||
324 | Linear in `this->size()`. | ||
325 | |||
326 | @par Exception Safety | ||
327 | Calls to allocate may throw. | ||
328 | String tokens may throw exceptions. | ||
329 | |||
330 | @param opt The options for encoding. If | ||
331 | this parameter is omitted, the default | ||
332 | options are used. | ||
333 | |||
334 | @param token An optional string token. | ||
335 | If this parameter is omitted, then | ||
336 | a new `std::string` is returned. | ||
337 | Otherwise, the function return type | ||
338 | is the result type of the token. | ||
339 | |||
340 | @see | ||
341 | @ref encoding_opts, | ||
342 | @ref string_token::return_string. | ||
343 | */ | ||
344 | template<BOOST_URL_STRTOK_TPARAM> | ||
345 | BOOST_URL_STRTOK_RETURN | ||
346 | 3308 | decode( | |
347 | encoding_opts opt = {}, | ||
348 | BOOST_URL_STRTOK_ARG(token)) const | ||
349 | { | ||
350 | /* If you get a compile error here, it | ||
351 | means that the token you passed does | ||
352 | not meet the requirements stated | ||
353 | in the documentation. | ||
354 | */ | ||
355 | static_assert( | ||
356 | string_token::is_token< | ||
357 | StringToken>::value, | ||
358 | "Type requirements not met"); | ||
359 | |||
360 | 3308 | decode_impl(token, opt); | |
361 | 3308 | return token.result(); | |
362 | } | ||
363 | |||
364 | #ifndef BOOST_URL_DOCS | ||
365 | // arrow support | ||
366 | pct_string_view const* | ||
367 | 93 | operator->() const noexcept | |
368 | { | ||
369 | 93 | return this; | |
370 | } | ||
371 | #endif | ||
372 | |||
373 | //-------------------------------------------- | ||
374 | |||
375 | // VFALCO No idea why this fails in msvc | ||
376 | /** Swap | ||
377 | */ | ||
378 | /*BOOST_CXX14_CONSTEXPR*/ void swap( | ||
379 | pct_string_view& s ) noexcept | ||
380 | { | ||
381 | string_view_base::swap(s); | ||
382 | std::swap(dn_, s.dn_); | ||
383 | } | ||
384 | }; | ||
385 | |||
386 | //------------------------------------------------ | ||
387 | |||
388 | #ifndef BOOST_URL_DOCS | ||
389 | namespace detail { | ||
390 | // obtain modifiable reference to | ||
391 | // underlying string, to handle | ||
392 | // self-intersection on modifiers. | ||
393 | inline | ||
394 | core::string_view& | ||
395 | 578 | ref(pct_string_view& s) noexcept | |
396 | { | ||
397 | 578 | return s.s_; | |
398 | } | ||
399 | |||
400 | } // detail | ||
401 | #endif | ||
402 | |||
403 | //------------------------------------------------ | ||
404 | |||
405 | /** Return a valid percent-encoded string | ||
406 | |||
407 | If `s` is a valid percent-encoded string, | ||
408 | the function returns the buffer as a valid | ||
409 | view which may be used to perform decoding | ||
410 | or measurements. | ||
411 | Otherwise the result contains an error code. | ||
412 | Upon success, the returned view references | ||
413 | the original character buffer; | ||
414 | Ownership is not transferred. | ||
415 | |||
416 | @par Complexity | ||
417 | Linear in `s.size()`. | ||
418 | |||
419 | @par Exception Safety | ||
420 | Throws nothing. | ||
421 | |||
422 | @param s The string to validate. | ||
423 | */ | ||
424 | BOOST_URL_DECL | ||
425 | system::result<pct_string_view> | ||
426 | make_pct_string_view( | ||
427 | core::string_view s) noexcept; | ||
428 | |||
429 | #ifndef BOOST_URL_DOCS | ||
430 | // VFALCO semi-private for now | ||
431 | inline | ||
432 | pct_string_view | ||
433 | 33744 | make_pct_string_view_unsafe( | |
434 | char const* data, | ||
435 | std::size_t size, | ||
436 | std::size_t decoded_size) noexcept | ||
437 | { | ||
438 | #if 0 | ||
439 | BOOST_ASSERT(! make_pct_string_view( | ||
440 | core::string_view(data, size)).has_error()); | ||
441 | #endif | ||
442 | return pct_string_view( | ||
443 | 33744 | data, size, decoded_size); | |
444 | } | ||
445 | #endif | ||
446 | |||
447 | #ifndef BOOST_URL_DOCS | ||
448 | namespace detail { | ||
449 | template <> | ||
450 | inline | ||
451 | core::string_view | ||
452 | 9685 | to_sv(pct_string_view const& s) noexcept | |
453 | { | ||
454 | 9685 | return s.substr(); | |
455 | } | ||
456 | } // detail | ||
457 | #endif | ||
458 | |||
459 | } // urls | ||
460 | } // boost | ||
461 | |||
462 | #endif | ||
463 |