Line data Source code
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 34583 : pct_string_view(
92 : char const* data,
93 : std::size_t size,
94 : std::size_t dn) noexcept
95 34583 : : string_view_base(data, size)
96 34583 : , dn_(dn)
97 : {
98 34583 : }
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 16491 : 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 931 : pct_string_view(
177 : String const& s)
178 : : pct_string_view(
179 931 : detail::to_sv(s))
180 : {
181 876 : }
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 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 : /** Return a valid percent-encoded string
267 :
268 : If `s` is a valid percent-encoded string,
269 : the function returns the buffer as a valid
270 : view which may be used to perform decoding
271 : or measurements.
272 : Otherwise the result contains an error code.
273 : Upon success, the returned view references
274 : the original character buffer;
275 : Ownership is not transferred.
276 :
277 : @par Complexity
278 : Linear in `s.size()`.
279 :
280 : @par Exception Safety
281 : Throws nothing.
282 :
283 : @param s The string to validate.
284 : */
285 : friend
286 : BOOST_URL_DECL
287 : system::result<pct_string_view>
288 : make_pct_string_view(
289 : core::string_view s) noexcept;
290 :
291 : //--------------------------------------------
292 :
293 : /** Return the decoded size
294 :
295 : This function returns the number of
296 : characters in the resulting string if
297 : percent escapes were converted into
298 : ordinary characters.
299 :
300 : @par Complexity
301 : Constant.
302 :
303 : @par Exception Safety
304 : Throws nothing.
305 : */
306 : std::size_t
307 14698 : decoded_size() const noexcept
308 : {
309 14698 : return dn_;
310 : }
311 :
312 : /** Return the string as a range of decoded characters
313 :
314 : @par Complexity
315 : Constant.
316 :
317 : @par Exception Safety
318 : Throws nothing.
319 :
320 : @see
321 : @ref decode_view.
322 : */
323 : decode_view
324 : operator*() const noexcept;
325 :
326 : /** Return the string with percent-decoding
327 :
328 : This function converts percent escapes
329 : in the string into ordinary characters
330 : and returns the result.
331 : When called with no arguments, the
332 : return type is `std::string`.
333 : Otherwise, the return type and style
334 : of output is determined by which string
335 : token is passed.
336 :
337 : @par Example
338 : @code
339 : assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" );
340 : @endcode
341 :
342 : @par Complexity
343 : Linear in `this->size()`.
344 :
345 : @par Exception Safety
346 : Calls to allocate may throw.
347 : String tokens may throw exceptions.
348 :
349 : @param opt The options for encoding. If
350 : this parameter is omitted, the default
351 : options are used.
352 :
353 : @param token An optional string token.
354 : If this parameter is omitted, then
355 : a new `std::string` is returned.
356 : Otherwise, the function return type
357 : is the result type of the token.
358 :
359 : @see
360 : @ref encoding_opts,
361 : @ref string_token::return_string.
362 : */
363 : template<BOOST_URL_STRTOK_TPARAM>
364 : BOOST_URL_STRTOK_RETURN
365 3302 : decode(
366 : encoding_opts opt = {},
367 : BOOST_URL_STRTOK_ARG(token)) const
368 : {
369 : /* If you get a compile error here, it
370 : means that the token you passed does
371 : not meet the requirements stated
372 : in the documentation.
373 : */
374 : static_assert(
375 : string_token::is_token<
376 : StringToken>::value,
377 : "Type requirements not met");
378 :
379 3302 : decode_impl(token, opt);
380 3302 : return token.result();
381 : }
382 :
383 : #ifndef BOOST_URL_DOCS
384 : /// Arrow support
385 : pct_string_view const*
386 93 : operator->() const noexcept
387 : {
388 93 : return this;
389 : }
390 : #endif
391 :
392 : //--------------------------------------------
393 :
394 : // VFALCO No idea why this fails in msvc
395 : /** Swap
396 : */
397 : /*BOOST_CXX14_CONSTEXPR*/ void swap(
398 : pct_string_view& s ) noexcept
399 : {
400 : string_view_base::swap(s);
401 : std::swap(dn_, s.dn_);
402 : }
403 : };
404 :
405 : //------------------------------------------------
406 :
407 : #ifndef BOOST_URL_DOCS
408 : namespace detail {
409 : // obtain modifiable reference to
410 : // underlying string, to handle
411 : // self-intersection on modifiers.
412 : inline
413 : core::string_view&
414 578 : ref(pct_string_view& s) noexcept
415 : {
416 578 : return s.s_;
417 : }
418 :
419 : } // detail
420 : #endif
421 :
422 : //------------------------------------------------
423 :
424 : /** Return a valid percent-encoded string
425 :
426 : If `s` is a valid percent-encoded string,
427 : the function returns the buffer as a valid
428 : view which may be used to perform decoding
429 : or measurements.
430 : Otherwise the result contains an error code.
431 : Upon success, the returned view references
432 : the original character buffer;
433 : Ownership is not transferred.
434 :
435 : @par Complexity
436 : Linear in `s.size()`.
437 :
438 : @par Exception Safety
439 : Throws nothing.
440 :
441 : @param s The string to validate.
442 : */
443 : BOOST_URL_DECL
444 : system::result<pct_string_view>
445 : make_pct_string_view(
446 : core::string_view s) noexcept;
447 :
448 : #ifndef BOOST_URL_DOCS
449 : // VFALCO semi-private for now
450 : inline
451 : pct_string_view
452 34583 : make_pct_string_view_unsafe(
453 : char const* data,
454 : std::size_t size,
455 : std::size_t decoded_size) noexcept
456 : {
457 : #if 0
458 : BOOST_ASSERT(! make_pct_string_view(
459 : core::string_view(data, size)).has_error());
460 : #endif
461 : return pct_string_view(
462 34583 : data, size, decoded_size);
463 : }
464 : #endif
465 :
466 : #ifndef BOOST_URL_DOCS
467 : namespace detail {
468 : template <>
469 : inline
470 : core::string_view
471 9865 : to_sv(pct_string_view const& s) noexcept
472 : {
473 9865 : return s.substr();
474 : }
475 : } // detail
476 : #endif
477 :
478 : } // urls
479 : } // boost
480 :
481 : #endif
|