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 34240 : pct_string_view(
92 : char const* data,
93 : std::size_t size,
94 : std::size_t dn) noexcept
95 34240 : : string_view_base(data, size)
96 34240 : , dn_(dn)
97 : {
98 34240 : }
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 16381 : 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 : 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 14636 : decoded_size() const noexcept
289 : {
290 14636 : 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 3297 : 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 3297 : decode_impl(token, opt);
361 3297 : 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 34240 : 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 34240 : 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 9845 : to_sv(pct_string_view const& s) noexcept
453 : {
454 9845 : return s.substr();
455 : }
456 : } // detail
457 : #endif
458 :
459 : } // urls
460 : } // boost
461 :
462 : #endif
|