Line data Source code
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 : class decode_view
73 : {
74 : char const* p_ = nullptr;
75 : std::size_t n_ = 0;
76 : std::size_t dn_ = 0;
77 : bool space_as_plus_ = true;
78 :
79 : #ifndef BOOST_URL_DOCS
80 : template<class... Args>
81 : friend
82 : decode_view
83 : detail::make_decode_view(
84 : Args&&... args) noexcept;
85 : #endif
86 :
87 : // unchecked
88 : BOOST_CXX14_CONSTEXPR
89 : explicit
90 3773 : decode_view(
91 : core::string_view s,
92 : std::size_t n,
93 : encoding_opts opt) noexcept
94 3773 : : p_(s.data())
95 3773 : , n_(s.size())
96 3773 : , dn_(n)
97 3773 : , space_as_plus_(
98 3773 : opt.space_as_plus)
99 3773 : {}
100 :
101 : public:
102 : /** The value type
103 : */
104 : using value_type = char;
105 :
106 : /** The reference type
107 : */
108 : using reference = char;
109 :
110 : /// @copydoc reference
111 : using const_reference = char;
112 :
113 : /** The unsigned integer type
114 : */
115 : using size_type = std::size_t;
116 :
117 : /** The signed integer type
118 : */
119 : using difference_type = std::ptrdiff_t;
120 :
121 : /** An iterator of constant, decoded characters.
122 :
123 : This iterator is used to access the encoded
124 : string as a *bidirectional* range of characters
125 : with percent-decoding applied. Escape sequences
126 : are not decoded until the iterator is
127 : dereferenced.
128 : */
129 : class iterator;
130 :
131 : /// @copydoc iterator
132 : using const_iterator = iterator;
133 :
134 : //--------------------------------------------
135 : //
136 : // Special Members
137 : //
138 : //--------------------------------------------
139 :
140 : /** Constructor
141 :
142 : Default-constructed views represent
143 : empty strings.
144 :
145 : @par Example
146 : @code
147 : decode_view ds;
148 : @endcode
149 :
150 : @par Postconditions
151 : @code
152 : this->empty() == true
153 : @endcode
154 :
155 : @par Complexity
156 : Constant.
157 :
158 : @par Exception Safety
159 : Throws nothing.
160 : */
161 : BOOST_CXX14_CONSTEXPR
162 : decode_view() noexcept = default;
163 :
164 : /** Constructor
165 :
166 : This constructs a view from the character
167 : buffer `s`, which must remain valid and
168 : unmodified until the view is no longer
169 : accessed.
170 :
171 : @par Example
172 : @code
173 : decode_view ds( "Program%20Files" );
174 : @endcode
175 :
176 : @par Postconditions
177 : @code
178 : this->encoded() == s
179 : @endcode
180 :
181 : @par Complexity
182 : Linear in `s.size()`.
183 :
184 : @par Exception Safety
185 : Although this function does not throw exceptions,
186 : implicitly constructing a @ref pct_string_view
187 : for the first argument can throw exceptions
188 : on invalid input.
189 :
190 : @param s A percent-encoded string that has
191 : already been validated. Implicit conversion
192 : from other string types is supported but
193 : may throw exceptions.
194 :
195 : @param opt The options for decoding. If
196 : this parameter is omitted, the default
197 : options are used.
198 : */
199 : BOOST_CXX14_CONSTEXPR
200 : explicit
201 3773 : decode_view(
202 : pct_string_view s,
203 : encoding_opts opt = {}) noexcept
204 3773 : : decode_view(
205 : detail::to_sv(s),
206 : s.decoded_size(),
207 3773 : opt)
208 : {
209 3773 : }
210 :
211 : //--------------------------------------------
212 : //
213 : // Observers
214 : //
215 : //--------------------------------------------
216 :
217 : /** Return true if the string is empty
218 :
219 : @par Example
220 : @code
221 : assert( decode_view( "" ).empty() );
222 : @endcode
223 :
224 : @par Complexity
225 : Constant.
226 :
227 : @par Exception Safety
228 : Throws nothing.
229 : */
230 : bool
231 15 : empty() const noexcept
232 : {
233 15 : return n_ == 0;
234 : }
235 :
236 : /** Return the number of decoded characters
237 :
238 : @par Example
239 : @code
240 : assert( decode_view( "Program%20Files" ).size() == 13 );
241 : @endcode
242 :
243 : @par Effects
244 : @code
245 : return std::distance( this->begin(), this->end() );
246 : @endcode
247 :
248 : @par Complexity
249 : Constant.
250 :
251 : @par Exception Safety
252 : Throws nothing.
253 : */
254 : size_type
255 3948 : size() const noexcept
256 : {
257 3948 : return dn_;
258 : }
259 :
260 : /** Return an iterator to the beginning
261 :
262 : @par Example
263 : @code
264 : auto it = this->begin();
265 : @endcode
266 :
267 : @par Complexity
268 : Constant.
269 :
270 : @par Exception Safety
271 : Throws nothing.
272 : */
273 : iterator
274 : begin() const noexcept;
275 :
276 : /** Return an iterator to the end
277 :
278 : @par Example
279 : @code
280 : auto it = this->end();
281 : @endcode
282 :
283 : @par Complexity
284 : Constant.
285 :
286 : @par Exception Safety
287 : Throws nothing.
288 : */
289 : iterator
290 : end() const noexcept;
291 :
292 : /** Return the first character
293 :
294 : @par Example
295 : @code
296 : assert( decode_view( "Program%20Files" ).front() == 'P' );
297 : @endcode
298 :
299 : @par Preconditions
300 : @code
301 : not this->empty()
302 : @endcode
303 :
304 : @par Complexity
305 : Constant.
306 :
307 : @par Exception Safety
308 : Throws nothing.
309 : */
310 : reference
311 : front() const noexcept;
312 :
313 : /** Return the last character
314 :
315 : @par Example
316 : @code
317 : assert( decode_view( "Program%20Files" ).back() == 's' );
318 : @endcode
319 :
320 : @par Preconditions
321 : @code
322 : not this->empty()
323 : @endcode
324 :
325 : @par Complexity
326 : Constant.
327 :
328 : @par Exception Safety
329 : Throws nothing.
330 : */
331 : reference
332 : back() const noexcept;
333 :
334 : /** Checks if the string begins with the given prefix
335 :
336 : @par Example
337 : @code
338 : assert( decode_view( "Program%20Files" ).starts_with("Program") );
339 : @endcode
340 :
341 : @par Complexity
342 : Linear.
343 :
344 : @par Exception Safety
345 : Throws nothing.
346 : */
347 : BOOST_URL_DECL
348 : bool
349 : starts_with( core::string_view s ) const noexcept;
350 :
351 : /** Checks if the string ends with the given prefix
352 :
353 : @par Example
354 : @code
355 : assert( decode_view( "Program%20Files" ).ends_with("Files") );
356 : @endcode
357 :
358 : @par Complexity
359 : Linear.
360 :
361 : @par Exception Safety
362 : Throws nothing.
363 : */
364 : BOOST_URL_DECL
365 : bool
366 : ends_with( core::string_view s ) const noexcept;
367 :
368 : /** Checks if the string begins with the given prefix
369 :
370 : @par Example
371 : @code
372 : assert( decode_view( "Program%20Files" ).starts_with('P') );
373 : @endcode
374 :
375 : @par Complexity
376 : Constant.
377 :
378 : @par Exception Safety
379 : Throws nothing.
380 : */
381 : BOOST_URL_DECL
382 : bool
383 : starts_with( char ch ) const noexcept;
384 :
385 : /** Checks if the string ends with the given prefix
386 :
387 : @par Example
388 : @code
389 : assert( decode_view( "Program%20Files" ).ends_with('s') );
390 : @endcode
391 :
392 : @par Complexity
393 : Constant.
394 :
395 : @par Exception Safety
396 : Throws nothing.
397 : */
398 : BOOST_URL_DECL
399 : bool
400 : ends_with( char ch ) const noexcept;
401 :
402 : /** Finds the first occurrence of character in this view
403 :
404 : @par Complexity
405 : Linear.
406 :
407 : @par Exception Safety
408 : Throws nothing.
409 : */
410 : BOOST_URL_DECL
411 : const_iterator
412 : find( char ch ) const noexcept;
413 :
414 : /** Finds the first occurrence of character in this view
415 :
416 : @par Complexity
417 : Linear.
418 :
419 : @par Exception Safety
420 : Throws nothing.
421 : */
422 : BOOST_URL_DECL
423 : const_iterator
424 : rfind( char ch ) const noexcept;
425 :
426 : /** Remove the first characters
427 :
428 : @par Example
429 : @code
430 : decode_view d( "Program%20Files" );
431 : d.remove_prefix( 8 );
432 : assert( d == "Files" );
433 : @endcode
434 :
435 : @par Preconditions
436 : @code
437 : not this->empty()
438 : @endcode
439 :
440 : @par Complexity
441 : Linear.
442 : */
443 : BOOST_URL_DECL
444 : void
445 : remove_prefix( size_type n );
446 :
447 : /** Remove the last characters
448 :
449 : @par Example
450 : @code
451 : decode_view d( "Program%20Files" );
452 : d.remove_prefix( 6 );
453 : assert( d == "Program" );
454 : @endcode
455 :
456 : @par Preconditions
457 : @code
458 : not this->empty()
459 : @endcode
460 :
461 : @par Complexity
462 : Linear.
463 : */
464 : BOOST_URL_DECL
465 : void
466 : remove_suffix( size_type n );
467 :
468 : /** Return the decoding options
469 : */
470 : encoding_opts
471 : options() const noexcept
472 : {
473 : encoding_opts opt;
474 : opt.space_as_plus = space_as_plus_;
475 : return opt;
476 : }
477 :
478 : //--------------------------------------------
479 : //
480 : // Comparison
481 : //
482 : //--------------------------------------------
483 :
484 : /** Return the result of comparing to another string
485 :
486 : The length of the sequences to compare is the smaller of
487 : `size()` and `other.size()`.
488 :
489 : The function compares the two strings as if by calling
490 : `char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
491 : This means the comparison is performed with
492 : percent-decoding applied to the current string.
493 :
494 : @param other string to compare
495 :
496 : @return Negative value if this string is less than the other
497 : character sequence, zero if the both character sequences are
498 : equal, positive value if this string is greater than the other
499 : character sequence
500 : */
501 : BOOST_CXX14_CONSTEXPR
502 : int
503 : compare(core::string_view other) const noexcept;
504 :
505 : /** Return the result of comparing to another string
506 :
507 : The length of the sequences to compare is the smaller of
508 : `size()` and `other.size()`.
509 :
510 : The function compares the two strings as if by calling
511 : `char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
512 : This means the comparison is performed with
513 : percent-decoding applied to the current string.
514 :
515 : @param other string to compare
516 :
517 : @return Negative value if this string is less than the other
518 : character sequence, zero if the both character sequences are
519 : equal, positive value if this string is greater than the other
520 : character sequence
521 : */
522 : BOOST_CXX14_CONSTEXPR
523 : int
524 : compare(decode_view other) const noexcept;
525 :
526 : //--------------------------------------------
527 :
528 : // relational operators
529 : private:
530 : template<class S0, class S1>
531 : using is_match = std::integral_constant<bool,
532 : // both decode_view or convertible to core::string_view
533 : (
534 : std::is_same<typename std::decay<S0>::type, decode_view>::value ||
535 : std::is_convertible<S0, core::string_view>::value) &&
536 : (
537 : std::is_same<typename std::decay<S1>::type, decode_view>::value ||
538 : std::is_convertible<S1, core::string_view>::value) &&
539 : // not both are convertible to string view
540 : (
541 : !std::is_convertible<S0, core::string_view>::value ||
542 : !std::is_convertible<S1, core::string_view>::value)>;
543 :
544 : BOOST_CXX14_CONSTEXPR
545 : static
546 : int
547 316 : decode_compare(decode_view s0, decode_view s1) noexcept
548 : {
549 316 : return s0.compare(s1);
550 : }
551 :
552 : template <class S>
553 : BOOST_CXX14_CONSTEXPR
554 : static
555 : int
556 2926 : decode_compare(decode_view s0, S const& s1) noexcept
557 : {
558 2926 : return s0.compare(s1);
559 : }
560 :
561 : template <class S>
562 : BOOST_CXX14_CONSTEXPR
563 : static
564 : int
565 : decode_compare(S const& s0, decode_view s1) noexcept
566 : {
567 : return -s1.compare(s0);
568 : }
569 :
570 : public:
571 : #ifndef BOOST_URL_HAS_CONCEPTS
572 : /// Compare two decode views for equality
573 : template<class S0, class S1>
574 2471 : BOOST_CXX14_CONSTEXPR friend auto operator==(
575 : S0 const& lhs, S1 const& rhs) noexcept ->
576 : typename std::enable_if<
577 : is_match<S0, S1>::value, bool>::type
578 : {
579 2471 : return decode_compare(lhs, rhs) == 0;
580 : }
581 : #else
582 : /// Compare two decode views for equality
583 : BOOST_CXX14_CONSTEXPR
584 : friend
585 : bool
586 : operator==(
587 : decode_view const& lhs,
588 : decode_view const& rhs) noexcept
589 : {
590 : return decode_compare(lhs, rhs) == 0;
591 : }
592 :
593 : /// Compare two decode views for equality
594 : template <std::convertible_to<core::string_view> S>
595 : BOOST_CXX14_CONSTEXPR
596 : friend
597 : bool
598 : operator==(
599 : decode_view const& lhs,
600 : S const& rhs) noexcept
601 : {
602 : return decode_compare(lhs, rhs) == 0;
603 : }
604 :
605 : /// Compare two decode views for equality
606 : template <std::convertible_to<core::string_view> S>
607 : BOOST_CXX14_CONSTEXPR
608 : friend
609 : bool
610 : operator==(
611 : S const& lhs,
612 : decode_view const& rhs) noexcept
613 : {
614 : return decode_compare(lhs, rhs) == 0;
615 : }
616 : #endif
617 :
618 : #ifndef BOOST_URL_HAS_CONCEPTS
619 : /// Compare two decode views for inequality
620 : template<class S0, class S1>
621 739 : BOOST_CXX14_CONSTEXPR friend auto operator!=(
622 : S0 const& lhs, S1 const& rhs) noexcept ->
623 : typename std::enable_if<
624 : is_match<S0, S1>::value, bool>::type
625 : {
626 739 : return decode_compare(lhs, rhs) != 0;
627 : }
628 : #else
629 : /// Compare two decode views for inequality
630 : BOOST_CXX14_CONSTEXPR
631 : friend
632 : bool
633 : operator!=(
634 : decode_view const& lhs,
635 : decode_view const& rhs) noexcept
636 : {
637 : return decode_compare(lhs, rhs) != 0;
638 : }
639 :
640 : /// Compare two decode views for inequality
641 : template <std::convertible_to<core::string_view> S>
642 : BOOST_CXX14_CONSTEXPR
643 : friend
644 : bool
645 : operator!=(
646 : decode_view const& lhs,
647 : S const& rhs) noexcept
648 : {
649 : return decode_compare(lhs, rhs) != 0;
650 : }
651 :
652 : /// Compare two decode views for inequality
653 : template <std::convertible_to<core::string_view> S>
654 : BOOST_CXX14_CONSTEXPR
655 : friend
656 : bool
657 : operator!=(
658 : S const& lhs,
659 : decode_view const& rhs) noexcept
660 : {
661 : return decode_compare(lhs, rhs) != 0;
662 : }
663 : #endif
664 :
665 : #ifndef BOOST_URL_HAS_CONCEPTS
666 : /// Compare two decode views for less than
667 : template<class S0, class S1>
668 8 : BOOST_CXX14_CONSTEXPR friend auto operator<(
669 : S0 const& lhs, S1 const& rhs) noexcept ->
670 : typename std::enable_if<
671 : is_match<S0, S1>::value, bool>::type
672 : {
673 8 : return decode_compare(lhs, rhs) < 0;
674 : }
675 : #else
676 : /// Compare two decode views for less than
677 : BOOST_CXX14_CONSTEXPR
678 : friend
679 : bool
680 : operator<(
681 : decode_view const& lhs,
682 : decode_view const& rhs) noexcept
683 : {
684 : return decode_compare(lhs, rhs) < 0;
685 : }
686 :
687 : /// Compare two decode views for less than
688 : template <std::convertible_to<core::string_view> S>
689 : BOOST_CXX14_CONSTEXPR
690 : friend
691 : bool
692 : operator<(
693 : decode_view const& lhs,
694 : S const& rhs) noexcept
695 : {
696 : return decode_compare(lhs, rhs) < 0;
697 : }
698 :
699 : /// Compare two decode views for less than
700 : template <std::convertible_to<core::string_view> S>
701 : BOOST_CXX14_CONSTEXPR
702 : friend
703 : bool
704 : operator<(
705 : S const& lhs,
706 : decode_view const& rhs) noexcept
707 : {
708 : return decode_compare(lhs, rhs) < 0;
709 : }
710 : #endif
711 :
712 : #ifndef BOOST_URL_HAS_CONCEPTS
713 : /// Compare two decode views for less than or equal
714 : template<class S0, class S1>
715 8 : BOOST_CXX14_CONSTEXPR friend auto operator<=(
716 : S0 const& lhs, S1 const& rhs) noexcept ->
717 : typename std::enable_if<
718 : is_match<S0, S1>::value, bool>::type
719 : {
720 8 : return decode_compare(lhs, rhs) <= 0;
721 : }
722 : #else
723 : /// Compare two decode views for less than or equal
724 : BOOST_CXX14_CONSTEXPR
725 : friend
726 : bool
727 : operator<=(
728 : decode_view const& lhs,
729 : decode_view const& rhs) noexcept
730 : {
731 : return decode_compare(lhs, rhs) <= 0;
732 : }
733 :
734 : /// Compare two decode views for less than or equal
735 : template <std::convertible_to<core::string_view> S>
736 : BOOST_CXX14_CONSTEXPR
737 : friend
738 : bool
739 : operator<=(
740 : decode_view const& lhs,
741 : S const& rhs) noexcept
742 : {
743 : return decode_compare(lhs, rhs) <= 0;
744 : }
745 :
746 : /// Compare two decode views for less than or equal
747 : template <std::convertible_to<core::string_view> S>
748 : BOOST_CXX14_CONSTEXPR
749 : friend
750 : bool
751 : operator<=(
752 : S const& lhs,
753 : decode_view const& rhs) noexcept
754 : {
755 : return decode_compare(lhs, rhs) <= 0;
756 : }
757 : #endif
758 :
759 : #ifndef BOOST_URL_HAS_CONCEPTS
760 : /// Compare two decode views for greater than
761 : template<class S0, class S1>
762 8 : BOOST_CXX14_CONSTEXPR friend auto operator>(
763 : S0 const& lhs, S1 const& rhs) noexcept ->
764 : typename std::enable_if<
765 : is_match<S0, S1>::value, bool>::type
766 : {
767 8 : return decode_compare(lhs, rhs) > 0;
768 : }
769 : #else
770 : /// Compare two decode views for greater than
771 : BOOST_CXX14_CONSTEXPR
772 : friend
773 : bool
774 : operator>(
775 : decode_view const& lhs,
776 : decode_view const& rhs) noexcept
777 : {
778 : return decode_compare(lhs, rhs) > 0;
779 : }
780 :
781 : /// Compare two decode views for greater than
782 : template <std::convertible_to<core::string_view> S>
783 : BOOST_CXX14_CONSTEXPR
784 : friend
785 : bool
786 : operator>(
787 : decode_view const& lhs,
788 : S const& rhs) noexcept
789 : {
790 : return decode_compare(lhs, rhs) > 0;
791 : }
792 :
793 : /// Compare two decode views for greater than
794 : template <std::convertible_to<core::string_view> S>
795 : BOOST_CXX14_CONSTEXPR
796 : friend
797 : bool
798 : operator>(
799 : S const& lhs,
800 : decode_view const& rhs) noexcept
801 : {
802 : return decode_compare(lhs, rhs) > 0;
803 : }
804 : #endif
805 :
806 : #ifndef BOOST_URL_HAS_CONCEPTS
807 : /// Compare two decode views for greater than or equal
808 : template<class S0, class S1>
809 8 : BOOST_CXX14_CONSTEXPR friend auto operator>=(
810 : S0 const& lhs, S1 const& rhs) noexcept ->
811 : typename std::enable_if<
812 : is_match<S0, S1>::value, bool>::type
813 : {
814 8 : return decode_compare(lhs, rhs) >= 0;
815 : }
816 : #else
817 : /// Compare two decode views for greater than or equal
818 : BOOST_CXX14_CONSTEXPR
819 : friend
820 : bool
821 : operator>=(
822 : decode_view const& lhs,
823 : decode_view const& rhs) noexcept
824 : {
825 : return decode_compare(lhs, rhs) >= 0;
826 : }
827 :
828 : /// Compare two decode views for greater than or equal
829 : template <std::convertible_to<core::string_view> S>
830 : BOOST_CXX14_CONSTEXPR
831 : friend
832 : bool
833 : operator>=(
834 : decode_view const& lhs,
835 : S const& rhs) noexcept
836 : {
837 : return decode_compare(lhs, rhs) >= 0;
838 : }
839 :
840 : /// Compare two decode views for greater than or equal
841 : template <std::convertible_to<core::string_view> S>
842 : BOOST_CXX14_CONSTEXPR
843 : friend
844 : bool
845 : operator>=(
846 : S const& lhs,
847 : decode_view const& rhs) noexcept
848 : {
849 : return decode_compare(lhs, rhs) >= 0;
850 : }
851 : #endif
852 :
853 : /** Format the string with percent-decoding applied to the output stream
854 :
855 : This hidden friend function serializes the decoded view
856 : to the output stream.
857 :
858 : @return A reference to the output stream, for chaining
859 :
860 : @param os The output stream to write to
861 :
862 : @param s The decoded view to write
863 : */
864 : friend
865 : std::ostream&
866 2 : operator<<(
867 : std::ostream& os,
868 : decode_view const& s)
869 : {
870 : // hidden friend
871 2 : s.write(os);
872 2 : return os;
873 : }
874 :
875 : private:
876 : BOOST_URL_DECL
877 : void
878 : write(std::ostream& os) const;
879 : };
880 :
881 : /** Format the string with percent-decoding applied to the output stream
882 :
883 : This function serializes the decoded view
884 : to the output stream.
885 :
886 : @return A reference to the output stream, for chaining
887 :
888 : @param os The output stream to write to
889 :
890 : @param s The decoded view to write
891 : */
892 : inline
893 : std::ostream&
894 : operator<<(
895 : std::ostream& os,
896 : decode_view const& s);
897 :
898 : //------------------------------------------------
899 :
900 : inline
901 : decode_view
902 3697 : pct_string_view::operator*() const noexcept
903 : {
904 3697 : return decode_view(*this);
905 : }
906 :
907 : #ifndef BOOST_URL_DOCS
908 : namespace detail {
909 : template<class... Args>
910 : decode_view
911 : make_decode_view(
912 : Args&&... args) noexcept
913 : {
914 : return decode_view(
915 : std::forward<Args>(args)...);
916 : }
917 : } // detail
918 : #endif
919 :
920 : //------------------------------------------------
921 :
922 : } // urls
923 : } // boost
924 :
925 : #include <boost/url/impl/decode_view.hpp>
926 :
927 : #endif
|