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