GCC Code Coverage Report


Directory: libs/url/
File: boost/url/decode_view.hpp
Date: 2024-03-05 20:06:57
Exec Total Coverage
Lines: 29 29 100.0%
Functions: 46 46 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2022 Alan de Freitas (alandefreitas@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_DECODE_VIEW_HPP
11 #define BOOST_URL_DECODE_VIEW_HPP
12
13 #include <boost/url/detail/config.hpp>
14 #include <boost/core/detail/string_view.hpp>
15 #include <boost/url/encoding_opts.hpp>
16 #include <boost/url/pct_string_view.hpp>
17 #include <type_traits>
18 #include <iterator>
19 #include <iosfwd>
20
21 namespace boost {
22 namespace urls {
23
24 //------------------------------------------------
25
26 #ifndef BOOST_URL_DOCS
27 class decode_view;
28
29 namespace detail {
30
31 // unchecked
32 template<class... Args>
33 decode_view
34 make_decode_view(
35 Args&&... args) noexcept;
36
37 } // detail
38 #endif
39
40 //------------------------------------------------
41
42 /** A reference to a valid, percent-encoded string
43
44 These views reference strings in parts of URLs
45 or other components that are percent-encoded.
46 The special characters (those not in the
47 allowed character set) are stored as three
48 character escapes that consist of a percent
49 sign ('%%') followed by a two-digit hexadecimal
50 number of the corresponding unescaped character
51 code, which may be part of a UTF-8 code point
52 depending on the context.
53
54 The view refers to the original character
55 buffer and only decodes escaped sequences when
56 needed. In particular these operations perform
57 percent-decoding automatically without the
58 need to allocate memory:
59
60 @li Iteration of the string
61 @li Accessing the encoded character buffer
62 @li Comparison to encoded or plain strings
63
64 These objects can only be constructed from
65 strings that have a valid percent-encoding,
66 otherwise construction fails. The caller is
67 responsible for ensuring that the lifetime
68 of the character buffer from which the view
69 is constructed extends unmodified until the
70 view is no longer accessed.
71
72 @par Operators
73 The following operators are supported between
74 @ref decode_view and any object that is convertible
75 to `core::string_view`
76
77 @code
78 bool operator==( decode_view, decode_view ) noexcept;
79 bool operator!=( decode_view, decode_view ) noexcept;
80 bool operator<=( decode_view, decode_view ) noexcept;
81 bool operator< ( decode_view, decode_view ) noexcept;
82 bool operator> ( decode_view, decode_view ) noexcept;
83 bool operator>=( decode_view, decode_view ) noexcept;
84 @endcode
85
86 */
87 class decode_view
88 {
89 char const* p_ = nullptr;
90 std::size_t n_ = 0;
91 std::size_t dn_ = 0;
92 bool space_as_plus_ = true;
93
94 #ifndef BOOST_URL_DOCS
95 template<class... Args>
96 friend
97 decode_view
98 detail::make_decode_view(
99 Args&&... args) noexcept;
100 #endif
101
102 // unchecked
103 BOOST_URL_DECL
104 explicit
105 decode_view(
106 core::string_view s,
107 std::size_t n,
108 encoding_opts opt) noexcept;
109
110 public:
111 /** The value type
112 */
113 using value_type = char;
114
115 /** The reference type
116 */
117 using reference = char;
118
119 /// @copydoc reference
120 using const_reference = char;
121
122 /** The unsigned integer type
123 */
124 using size_type = std::size_t;
125
126 /** The signed integer type
127 */
128 using difference_type = std::ptrdiff_t;
129
130 /** An iterator of constant, decoded characters.
131
132 This iterator is used to access the encoded
133 string as a bidirectional range of characters
134 with percent-decoding applied. Escape sequences
135 are not decoded until the iterator is
136 dereferenced.
137 */
138 #ifdef BOOST_URL_DOCS
139 using iterator = __see_below__;
140 #else
141 class iterator;
142 #endif
143
144 /// @copydoc iterator
145 using const_iterator = iterator;
146
147 //--------------------------------------------
148 //
149 // Special Members
150 //
151 //--------------------------------------------
152
153 /** Constructor
154
155 Default-constructed views represent
156 empty strings.
157
158 @par Example
159 @code
160 decode_view ds;
161 @endcode
162
163 @par Postconditions
164 @code
165 this->empty() == true
166 @endcode
167
168 @par Complexity
169 Constant.
170
171 @par Exception Safety
172 Throws nothing.
173 */
174 decode_view() noexcept = default;
175
176 /** Constructor
177
178 This constructs a view from the character
179 buffer `s`, which must remain valid and
180 unmodified until the view is no longer
181 accessed.
182
183 @par Example
184 @code
185 decode_view ds( "Program%20Files" );
186 @endcode
187
188 @par Postconditions
189 @code
190 this->encoded() == s
191 @endcode
192
193 @par Complexity
194 Linear in `s.size()`.
195
196 @par Exception Safety
197 Exceptions thrown on invalid input.
198
199 @throw system_error
200 The string contains an invalid percent encoding.
201
202 @param s A percent-encoded string that has
203 already been validated.
204
205 @param opt The options for decoding. If
206 this parameter is omitted, the default
207 options are used.
208 */
209 explicit
210 3765 decode_view(
211 pct_string_view s,
212 encoding_opts opt = {}) noexcept
213 3765 : decode_view(
214 detail::to_sv(s),
215 s.decoded_size(),
216 3765 opt)
217 {
218 3765 }
219
220 //--------------------------------------------
221 //
222 // Observers
223 //
224 //--------------------------------------------
225
226 /** Return true if the string is empty
227
228 @par Example
229 @code
230 assert( decode_view( "" ).empty() );
231 @endcode
232
233 @par Complexity
234 Constant.
235
236 @par Exception Safety
237 Throws nothing.
238 */
239 bool
240 15 empty() const noexcept
241 {
242 15 return n_ == 0;
243 }
244
245 /** Return the number of decoded characters
246
247 @par Example
248 @code
249 assert( decode_view( "Program%20Files" ).size() == 13 );
250 @endcode
251
252 @par Effects
253 @code
254 return std::distance( this->begin(), this->end() );
255 @endcode
256
257 @par Complexity
258 Constant.
259
260 @par Exception Safety
261 Throws nothing.
262 */
263 size_type
264 3936 size() const noexcept
265 {
266 3936 return dn_;
267 }
268
269 /** Return an iterator to the beginning
270
271 @par Example
272 @code
273 auto it = this->begin();
274 @endcode
275
276 @par Complexity
277 Constant.
278
279 @par Exception Safety
280 Throws nothing.
281 */
282 iterator
283 begin() const noexcept;
284
285 /** Return an iterator to the end
286
287 @par Example
288 @code
289 auto it = this->end();
290 @endcode
291
292 @par Complexity
293 Constant.
294
295 @par Exception Safety
296 Throws nothing.
297 */
298 iterator
299 end() const noexcept;
300
301 /** Return the first character
302
303 @par Example
304 @code
305 assert( decode_view( "Program%20Files" ).front() == 'P' );
306 @endcode
307
308 @par Preconditions
309 @code
310 not this->empty()
311 @endcode
312
313 @par Complexity
314 Constant.
315
316 @par Exception Safety
317 Throws nothing.
318 */
319 reference
320 front() const noexcept;
321
322 /** Return the last character
323
324 @par Example
325 @code
326 assert( decode_view( "Program%20Files" ).back() == 's' );
327 @endcode
328
329 @par Preconditions
330 @code
331 not this->empty()
332 @endcode
333
334 @par Complexity
335 Constant.
336
337 @par Exception Safety
338 Throws nothing.
339 */
340 reference
341 back() const noexcept;
342
343 /** Checks if the string begins with the given prefix
344
345 @par Example
346 @code
347 assert( decode_view( "Program%20Files" ).starts_with("Program") );
348 @endcode
349
350 @par Complexity
351 Linear.
352
353 @par Exception Safety
354 Throws nothing.
355 */
356 BOOST_URL_DECL
357 bool
358 starts_with( core::string_view s ) const noexcept;
359
360 /** Checks if the string ends with the given prefix
361
362 @par Example
363 @code
364 assert( decode_view( "Program%20Files" ).ends_with("Files") );
365 @endcode
366
367 @par Complexity
368 Linear.
369
370 @par Exception Safety
371 Throws nothing.
372 */
373 BOOST_URL_DECL
374 bool
375 ends_with( core::string_view s ) const noexcept;
376
377 /** Checks if the string begins with the given prefix
378
379 @par Example
380 @code
381 assert( decode_view( "Program%20Files" ).starts_with('P') );
382 @endcode
383
384 @par Complexity
385 Constant.
386
387 @par Exception Safety
388 Throws nothing.
389 */
390 BOOST_URL_DECL
391 bool
392 starts_with( char ch ) const noexcept;
393
394 /** Checks if the string ends with the given prefix
395
396 @par Example
397 @code
398 assert( decode_view( "Program%20Files" ).ends_with('s') );
399 @endcode
400
401 @par Complexity
402 Constant.
403
404 @par Exception Safety
405 Throws nothing.
406 */
407 BOOST_URL_DECL
408 bool
409 ends_with( char ch ) const noexcept;
410
411 /** Finds the first occurrence of character in this view
412
413 @par Complexity
414 Linear.
415
416 @par Exception Safety
417 Throws nothing.
418 */
419 BOOST_URL_DECL
420 const_iterator
421 find( char ch ) const noexcept;
422
423 /** Finds the first occurrence of character in this view
424
425 @par Complexity
426 Linear.
427
428 @par Exception Safety
429 Throws nothing.
430 */
431 BOOST_URL_DECL
432 const_iterator
433 rfind( char ch ) const noexcept;
434
435 /** Remove the first characters
436
437 @par Example
438 @code
439 decode_view d( "Program%20Files" );
440 d.remove_prefix( 8 );
441 assert( d == "Files" );
442 @endcode
443
444 @par Preconditions
445 @code
446 not this->empty()
447 @endcode
448
449 @par Complexity
450 Linear.
451 */
452 BOOST_URL_DECL
453 void
454 remove_prefix( size_type n );
455
456 /** Remove the last characters
457
458 @par Example
459 @code
460 decode_view d( "Program%20Files" );
461 d.remove_prefix( 6 );
462 assert( d == "Program" );
463 @endcode
464
465 @par Preconditions
466 @code
467 not this->empty()
468 @endcode
469
470 @par Complexity
471 Linear.
472 */
473 BOOST_URL_DECL
474 void
475 remove_suffix( size_type n );
476
477 /** Return the decoding options
478 */
479 encoding_opts
480 options() const noexcept
481 {
482 encoding_opts opt;
483 opt.space_as_plus = space_as_plus_;
484 return opt;
485 }
486
487 //--------------------------------------------
488 //
489 // Comparison
490 //
491 //--------------------------------------------
492
493 /** Return the result of comparing to another string
494
495 The length of the sequences to compare is the smaller of
496 `size()` and `other.size()`.
497
498 The function compares the two strings as if by calling
499 `char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
500 This means the comparison is performed with
501 percent-decoding applied to the current string.
502
503 @param other string to compare
504
505 @return Negative value if this string is less than the other
506 character sequence, zero if the both character sequences are
507 equal, positive value if this string is greater than the other
508 character sequence
509 */
510 BOOST_URL_DECL
511 int
512 compare(core::string_view other) const noexcept;
513
514 /** Return the result of comparing to another string
515
516 The length of the sequences to compare is the smaller of
517 `size()` and `other.size()`.
518
519 The function compares the two strings as if by calling
520 `char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
521 This means the comparison is performed with
522 percent-decoding applied to the current string.
523
524 @param other string to compare
525
526 @return Negative value if this string is less than the other
527 character sequence, zero if the both character sequences are
528 equal, positive value if this string is greater than the other
529 character sequence
530 */
531 BOOST_URL_DECL
532 int
533 compare(decode_view other) const noexcept;
534
535 //--------------------------------------------
536
537 // relational operators
538 #ifndef BOOST_URL_DOCS
539 private:
540 template<class S0, class S1>
541 using is_match = std::integral_constant<bool,
542 // both decode_view or convertible to core::string_view
543 (
544 std::is_same<typename std::decay<S0>::type, decode_view>::value ||
545 std::is_convertible<S0, core::string_view>::value) &&
546 (
547 std::is_same<typename std::decay<S1>::type, decode_view>::value ||
548 std::is_convertible<S1, core::string_view>::value) &&
549 // not both are convertible to string view
550 (
551 !std::is_convertible<S0, core::string_view>::value ||
552 !std::is_convertible<S1, core::string_view>::value)>;
553
554 static
555 int
556 316 decode_compare(decode_view s0, decode_view s1) noexcept
557 {
558 316 return s0.compare(s1);
559 }
560
561 template <class S>
562 static
563 int
564 5555 decode_compare(decode_view s0, S const& s1) noexcept
565 {
566 5555 return s0.compare(s1);
567 }
568
569 template <class S>
570 static
571 int
572 decode_compare(S const& s0, decode_view s1) noexcept
573 {
574 return -s1.compare(s0);
575 }
576 public:
577
578 template<class S0, class S1>
579 3315 BOOST_CXX14_CONSTEXPR friend auto operator==(
580 S0 const& s0, S1 const& s1) noexcept ->
581 typename std::enable_if<
582 is_match<S0, S1>::value, bool>::type
583 {
584 3315 return decode_compare(s0, s1) == 0;
585 }
586
587 template<class S0, class S1>
588 743 BOOST_CXX14_CONSTEXPR friend auto operator!=(
589 S0 const& s0, S1 const& s1) noexcept ->
590 typename std::enable_if<
591 is_match<S0, S1>::value, bool>::type
592 {
593 743 return decode_compare(s0, s1) != 0;
594 }
595
596 template<class S0, class S1>
597 16 BOOST_CXX14_CONSTEXPR friend auto operator<(
598 S0 const& s0, S1 const& s1) noexcept ->
599 typename std::enable_if<
600 is_match<S0, S1>::value, bool>::type
601 {
602 16 return decode_compare(s0, s1) < 0;
603 }
604
605 template<class S0, class S1>
606 16 BOOST_CXX14_CONSTEXPR friend auto operator<=(
607 S0 const& s0, S1 const& s1) noexcept ->
608 typename std::enable_if<
609 is_match<S0, S1>::value, bool>::type
610 {
611 16 return decode_compare(s0, s1) <= 0;
612 }
613
614 template<class S0, class S1>
615 16 BOOST_CXX14_CONSTEXPR friend auto operator>(
616 S0 const& s0, S1 const& s1) noexcept ->
617 typename std::enable_if<
618 is_match<S0, S1>::value, bool>::type
619 {
620 16 return decode_compare(s0, s1) > 0;
621 }
622
623 template<class S0, class S1>
624 16 BOOST_CXX14_CONSTEXPR friend auto operator>=(
625 S0 const& s0, S1 const& s1) noexcept ->
626 typename std::enable_if<
627 is_match<S0, S1>::value, bool>::type
628 {
629 16 return decode_compare(s0, s1) >= 0;
630 }
631 #endif
632
633 // hidden friend
634 friend
635 std::ostream&
636 2 operator<<(
637 std::ostream& os,
638 decode_view const& s)
639 {
640 // hidden friend
641 2 s.write(os);
642 2 return os;
643 }
644
645 private:
646 BOOST_URL_DECL
647 void
648 write(std::ostream& os) const;
649 };
650
651 /** Format the string with percent-decoding applied to the output stream
652
653 This function serializes the decoded view
654 to the output stream.
655
656 @return A reference to the output stream, for chaining
657
658 @param os The output stream to write to
659
660 @param s The decoded view to write
661 */
662 inline
663 std::ostream&
664 operator<<(
665 std::ostream& os,
666 decode_view const& s);
667
668 //------------------------------------------------
669
670 inline
671 decode_view
672 3689 pct_string_view::operator*() const noexcept
673 {
674 3689 return decode_view(*this);
675 }
676
677 #ifndef BOOST_URL_DOCS
678 namespace detail {
679 template<class... Args>
680 decode_view
681 make_decode_view(
682 Args&&... args) noexcept
683 {
684 return decode_view(
685 std::forward<Args>(args)...);
686 }
687 } // detail
688 #endif
689
690 //------------------------------------------------
691
692 } // urls
693 } // boost
694
695 #include <boost/url/impl/decode_view.hpp>
696
697 #endif
698