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