LCOV - code coverage report
Current view: top level - boost/url - decode_view.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 29 29 100.0 %
Date: 2024-03-05 20:06:56 Functions: 46 46 100.0 %

          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             :     @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        2918 :     decode_compare(decode_view s0, S const& s1) noexcept
     565             :     {
     566        2918 :         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        2467 :     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        2467 :         return decode_compare(s0, s1) == 0;
     585             :     }
     586             : 
     587             :     template<class S0, class S1>
     588         735 :     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         735 :         return decode_compare(s0, s1) != 0;
     594             :     }
     595             : 
     596             :     template<class S0, class S1>
     597           8 :     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           8 :         return decode_compare(s0, s1) < 0;
     603             :     }
     604             : 
     605             :     template<class S0, class S1>
     606           8 :     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           8 :         return decode_compare(s0, s1) <= 0;
     612             :     }
     613             : 
     614             :     template<class S0, class S1>
     615           8 :     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           8 :         return decode_compare(s0, s1) > 0;
     621             :     }
     622             : 
     623             :     template<class S0, class S1>
     624           8 :     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           8 :         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

Generated by: LCOV version 1.15