Line data 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 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
|