include/boost/url/pct_string_view.hpp

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