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

            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              : 
     142              :     /** An iterator of constant, decoded characters.
     143              : 
     144              :         This iterator is used to access the encoded
     145              :         string as a bidirectional range of characters
     146              :         with percent-decoding applied. Escape sequences
     147              :         are not decoded until the iterator is
     148              :         dereferenced.
     149              :     */
     150              :     class iterator;
     151              : #endif
     152              : 
     153              :     /// @copydoc iterator
     154              :     using const_iterator = iterator;
     155              : 
     156              :     //--------------------------------------------
     157              :     //
     158              :     // Special Members
     159              :     //
     160              :     //--------------------------------------------
     161              : 
     162              :     /** Constructor
     163              : 
     164              :         Default-constructed views represent
     165              :         empty strings.
     166              : 
     167              :         @par Example
     168              :         @code
     169              :         decode_view ds;
     170              :         @endcode
     171              : 
     172              :         @par Postconditions
     173              :         @code
     174              :         this->empty() == true
     175              :         @endcode
     176              : 
     177              :         @par Complexity
     178              :         Constant.
     179              : 
     180              :         @par Exception Safety
     181              :         Throws nothing.
     182              :     */
     183              :     decode_view() noexcept = default;
     184              : 
     185              :     /** Constructor
     186              : 
     187              :         This constructs a view from the character
     188              :         buffer `s`, which must remain valid and
     189              :         unmodified until the view is no longer
     190              :         accessed.
     191              : 
     192              :         @par Example
     193              :         @code
     194              :         decode_view ds( "Program%20Files" );
     195              :         @endcode
     196              : 
     197              :         @par Postconditions
     198              :         @code
     199              :         this->encoded() == s
     200              :         @endcode
     201              : 
     202              :         @par Complexity
     203              :         Linear in `s.size()`.
     204              : 
     205              :         @par Exception Safety
     206              :         Exceptions thrown on invalid input.
     207              : 
     208              :         @throw system_error
     209              :         The string contains an invalid percent encoding.
     210              : 
     211              :         @param s A percent-encoded string that has
     212              :         already been validated.
     213              : 
     214              :         @param opt The options for decoding. If
     215              :         this parameter is omitted, the default
     216              :         options are used.
     217              :     */
     218              :     explicit
     219         3773 :     decode_view(
     220              :         pct_string_view s,
     221              :         encoding_opts opt = {}) noexcept
     222         3773 :         : decode_view(
     223              :             detail::to_sv(s),
     224              :             s.decoded_size(),
     225         3773 :             opt)
     226              :     {
     227         3773 :     }
     228              : 
     229              :     //--------------------------------------------
     230              :     //
     231              :     // Observers
     232              :     //
     233              :     //--------------------------------------------
     234              : 
     235              :     /** Return true if the string is empty
     236              : 
     237              :         @par Example
     238              :         @code
     239              :         assert( decode_view( "" ).empty() );
     240              :         @endcode
     241              : 
     242              :         @par Complexity
     243              :         Constant.
     244              : 
     245              :         @par Exception Safety
     246              :         Throws nothing.
     247              :     */
     248              :     bool
     249           15 :     empty() const noexcept
     250              :     {
     251           15 :         return n_ == 0;
     252              :     }
     253              : 
     254              :     /** Return the number of decoded characters
     255              : 
     256              :         @par Example
     257              :         @code
     258              :         assert( decode_view( "Program%20Files" ).size() == 13 );
     259              :         @endcode
     260              : 
     261              :         @par Effects
     262              :         @code
     263              :         return std::distance( this->begin(), this->end() );
     264              :         @endcode
     265              : 
     266              :         @par Complexity
     267              :         Constant.
     268              : 
     269              :         @par Exception Safety
     270              :         Throws nothing.
     271              :     */
     272              :     size_type
     273         3948 :     size() const noexcept
     274              :     {
     275         3948 :         return dn_;
     276              :     }
     277              : 
     278              :     /** Return an iterator to the beginning
     279              : 
     280              :         @par Example
     281              :         @code
     282              :         auto it = this->begin();
     283              :         @endcode
     284              : 
     285              :         @par Complexity
     286              :         Constant.
     287              : 
     288              :         @par Exception Safety
     289              :         Throws nothing.
     290              :     */
     291              :     iterator
     292              :     begin() const noexcept;
     293              : 
     294              :     /** Return an iterator to the end
     295              : 
     296              :         @par Example
     297              :         @code
     298              :         auto it = this->end();
     299              :         @endcode
     300              : 
     301              :         @par Complexity
     302              :         Constant.
     303              : 
     304              :         @par Exception Safety
     305              :         Throws nothing.
     306              :     */
     307              :     iterator
     308              :     end() const noexcept;
     309              : 
     310              :     /** Return the first character
     311              : 
     312              :         @par Example
     313              :         @code
     314              :         assert( decode_view( "Program%20Files" ).front() == 'P' );
     315              :         @endcode
     316              : 
     317              :         @par Preconditions
     318              :         @code
     319              :         not this->empty()
     320              :         @endcode
     321              : 
     322              :         @par Complexity
     323              :         Constant.
     324              : 
     325              :         @par Exception Safety
     326              :         Throws nothing.
     327              :     */
     328              :     reference
     329              :     front() const noexcept;
     330              : 
     331              :     /** Return the last character
     332              : 
     333              :         @par Example
     334              :         @code
     335              :         assert( decode_view( "Program%20Files" ).back() == 's' );
     336              :         @endcode
     337              : 
     338              :         @par Preconditions
     339              :         @code
     340              :         not this->empty()
     341              :         @endcode
     342              : 
     343              :         @par Complexity
     344              :         Constant.
     345              : 
     346              :         @par Exception Safety
     347              :         Throws nothing.
     348              :     */
     349              :     reference
     350              :     back() const noexcept;
     351              : 
     352              :     /** Checks if the string begins with the given prefix
     353              : 
     354              :         @par Example
     355              :         @code
     356              :         assert( decode_view( "Program%20Files" ).starts_with("Program") );
     357              :         @endcode
     358              : 
     359              :         @par Complexity
     360              :         Linear.
     361              : 
     362              :         @par Exception Safety
     363              :         Throws nothing.
     364              :     */
     365              :     BOOST_URL_DECL
     366              :     bool
     367              :     starts_with( core::string_view s ) const noexcept;
     368              : 
     369              :     /** Checks if the string ends with the given prefix
     370              : 
     371              :         @par Example
     372              :         @code
     373              :         assert( decode_view( "Program%20Files" ).ends_with("Files") );
     374              :         @endcode
     375              : 
     376              :         @par Complexity
     377              :         Linear.
     378              : 
     379              :         @par Exception Safety
     380              :         Throws nothing.
     381              :     */
     382              :     BOOST_URL_DECL
     383              :     bool
     384              :     ends_with( core::string_view s ) const noexcept;
     385              : 
     386              :     /** Checks if the string begins with the given prefix
     387              : 
     388              :         @par Example
     389              :         @code
     390              :         assert( decode_view( "Program%20Files" ).starts_with('P') );
     391              :         @endcode
     392              : 
     393              :         @par Complexity
     394              :         Constant.
     395              : 
     396              :         @par Exception Safety
     397              :         Throws nothing.
     398              :     */
     399              :     BOOST_URL_DECL
     400              :     bool
     401              :     starts_with( char ch ) const noexcept;
     402              : 
     403              :     /** Checks if the string ends with the given prefix
     404              : 
     405              :         @par Example
     406              :         @code
     407              :         assert( decode_view( "Program%20Files" ).ends_with('s') );
     408              :         @endcode
     409              : 
     410              :         @par Complexity
     411              :         Constant.
     412              : 
     413              :         @par Exception Safety
     414              :         Throws nothing.
     415              :     */
     416              :     BOOST_URL_DECL
     417              :     bool
     418              :     ends_with( char ch ) const noexcept;
     419              : 
     420              :     /** Finds the first occurrence of character in this view
     421              : 
     422              :         @par Complexity
     423              :         Linear.
     424              : 
     425              :         @par Exception Safety
     426              :         Throws nothing.
     427              :     */
     428              :     BOOST_URL_DECL
     429              :     const_iterator
     430              :     find( char ch ) const noexcept;
     431              : 
     432              :     /** Finds the first occurrence of character in this view
     433              : 
     434              :         @par Complexity
     435              :         Linear.
     436              : 
     437              :         @par Exception Safety
     438              :         Throws nothing.
     439              :     */
     440              :     BOOST_URL_DECL
     441              :     const_iterator
     442              :     rfind( char ch ) const noexcept;
     443              : 
     444              :     /** Remove the first characters
     445              : 
     446              :         @par Example
     447              :         @code
     448              :         decode_view d( "Program%20Files" );
     449              :         d.remove_prefix( 8 );
     450              :         assert( d == "Files" );
     451              :         @endcode
     452              : 
     453              :         @par Preconditions
     454              :         @code
     455              :         not this->empty()
     456              :         @endcode
     457              : 
     458              :         @par Complexity
     459              :         Linear.
     460              :     */
     461              :     BOOST_URL_DECL
     462              :     void
     463              :     remove_prefix( size_type n );
     464              : 
     465              :     /** Remove the last characters
     466              : 
     467              :         @par Example
     468              :         @code
     469              :         decode_view d( "Program%20Files" );
     470              :         d.remove_prefix( 6 );
     471              :         assert( d == "Program" );
     472              :         @endcode
     473              : 
     474              :         @par Preconditions
     475              :         @code
     476              :         not this->empty()
     477              :         @endcode
     478              : 
     479              :         @par Complexity
     480              :         Linear.
     481              :     */
     482              :     BOOST_URL_DECL
     483              :     void
     484              :     remove_suffix( size_type n );
     485              : 
     486              :     /** Return the decoding options
     487              :     */
     488              :     encoding_opts
     489              :     options() const noexcept
     490              :     {
     491              :         encoding_opts opt;
     492              :         opt.space_as_plus = space_as_plus_;
     493              :         return opt;
     494              :     }
     495              : 
     496              :     //--------------------------------------------
     497              :     //
     498              :     // Comparison
     499              :     //
     500              :     //--------------------------------------------
     501              : 
     502              :     /** Return the result of comparing to another string
     503              : 
     504              :         The length of the sequences to compare is the smaller of
     505              :         `size()` and `other.size()`.
     506              : 
     507              :         The function compares the two strings as if by calling
     508              :         `char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
     509              :         This means the comparison is performed with
     510              :         percent-decoding applied to the current string.
     511              : 
     512              :         @param other string to compare
     513              : 
     514              :         @return Negative value if this string is less than the other
     515              :         character sequence, zero if the both character sequences are
     516              :         equal, positive value if this string is greater than the other
     517              :         character sequence
     518              :     */
     519              :     BOOST_URL_DECL
     520              :     int
     521              :     compare(core::string_view other) const noexcept;
     522              : 
     523              :     /** Return the result of comparing to another string
     524              : 
     525              :         The length of the sequences to compare is the smaller of
     526              :         `size()` and `other.size()`.
     527              : 
     528              :         The function compares the two strings as if by calling
     529              :         `char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
     530              :         This means the comparison is performed with
     531              :         percent-decoding applied to the current string.
     532              : 
     533              :         @param other string to compare
     534              : 
     535              :         @return Negative value if this string is less than the other
     536              :         character sequence, zero if the both character sequences are
     537              :         equal, positive value if this string is greater than the other
     538              :         character sequence
     539              :     */
     540              :     BOOST_URL_DECL
     541              :     int
     542              :     compare(decode_view other) const noexcept;
     543              : 
     544              :     //--------------------------------------------
     545              : 
     546              :     // relational operators
     547              : #ifndef BOOST_URL_DOCS
     548              : private:
     549              :     template<class S0, class S1>
     550              :     using is_match = std::integral_constant<bool,
     551              :         // both decode_view or convertible to core::string_view
     552              :         (
     553              :             std::is_same<typename std::decay<S0>::type, decode_view>::value ||
     554              :             std::is_convertible<S0, core::string_view>::value) &&
     555              :         (
     556              :             std::is_same<typename std::decay<S1>::type, decode_view>::value ||
     557              :             std::is_convertible<S1, core::string_view>::value) &&
     558              :         // not both are convertible to string view
     559              :         (
     560              :             !std::is_convertible<S0, core::string_view>::value ||
     561              :             !std::is_convertible<S1, core::string_view>::value)>;
     562              : 
     563              :     static
     564              :     int
     565          316 :     decode_compare(decode_view s0, decode_view s1) noexcept
     566              :     {
     567          316 :         return s0.compare(s1);
     568              :     }
     569              : 
     570              :     template <class S>
     571              :     static
     572              :     int
     573         2926 :     decode_compare(decode_view s0, S const& s1) noexcept
     574              :     {
     575         2926 :         return s0.compare(s1);
     576              :     }
     577              : 
     578              :     template <class S>
     579              :     static
     580              :     int
     581              :     decode_compare(S const& s0, decode_view s1) noexcept
     582              :     {
     583              :         return -s1.compare(s0);
     584              :     }
     585              : public:
     586              : 
     587              :     /// Compare two decode views for equality
     588              :     /**
     589              :      * This function is only enabled if both types are
     590              :      * decode_view or convertible to `core::string_view`,
     591              :      * but not both are convertible to `core::string_view`
     592              :      */
     593              :     template<class S0, class S1>
     594         2471 :     BOOST_CXX14_CONSTEXPR friend auto operator==(
     595              :         S0 const& s0, S1 const& s1) noexcept ->
     596              :         typename std::enable_if<
     597              :             is_match<S0, S1>::value, bool>::type
     598              :     {
     599         2471 :         return decode_compare(s0, s1) == 0;
     600              :     }
     601              : 
     602              :     /// Compare two decode views for inequality
     603              :     /**
     604              :      * This function is only enabled if both types are
     605              :      * decode_view or convertible to `core::string_view`,
     606              :      * but not both are convertible to `core::string_view`
     607              :      */
     608              :     template<class S0, class S1>
     609          739 :     BOOST_CXX14_CONSTEXPR friend auto operator!=(
     610              :         S0 const& s0, S1 const& s1) noexcept ->
     611              :         typename std::enable_if<
     612              :             is_match<S0, S1>::value, bool>::type
     613              :     {
     614          739 :         return decode_compare(s0, s1) != 0;
     615              :     }
     616              : 
     617              :     /// Compare two decode views for less than
     618              :     /**
     619              :      * This function is only enabled if both types are
     620              :      * decode_view or convertible to `core::string_view`,
     621              :      * but not both are convertible to `core::string_view`
     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              : 
     632              :     /// Compare two decode views for less than or equal
     633              :     /**
     634              :      * This function is only enabled if both types are
     635              :      * decode_view or convertible to `core::string_view`,
     636              :      * but not both are convertible to `core::string_view`
     637              :      */
     638              :     template<class S0, class S1>
     639            8 :     BOOST_CXX14_CONSTEXPR friend auto operator<=(
     640              :         S0 const& s0, S1 const& s1) noexcept ->
     641              :         typename std::enable_if<
     642              :             is_match<S0, S1>::value, bool>::type
     643              :     {
     644            8 :         return decode_compare(s0, s1) <= 0;
     645              :     }
     646              : 
     647              :     /// Compare two decode views for greater than
     648              :     /**
     649              :      * This function is only enabled if both types are
     650              :      * decode_view or convertible to `core::string_view`,
     651              :      * but not both are convertible to `core::string_view`
     652              :      */
     653              :     template<class S0, class S1>
     654            8 :     BOOST_CXX14_CONSTEXPR friend auto operator>(
     655              :         S0 const& s0, S1 const& s1) noexcept ->
     656              :         typename std::enable_if<
     657              :             is_match<S0, S1>::value, bool>::type
     658              :     {
     659            8 :         return decode_compare(s0, s1) > 0;
     660              :     }
     661              : 
     662              :     /// Compare two decode views for greater than or equal
     663              :     /**
     664              :      * This function is only enabled if both types are
     665              :      * decode_view or convertible to `core::string_view`,
     666              :      * but not both are convertible to `core::string_view`
     667              :      */
     668              :     template<class S0, class S1>
     669            8 :     BOOST_CXX14_CONSTEXPR friend auto operator>=(
     670              :         S0 const& s0, S1 const& s1) noexcept ->
     671              :         typename std::enable_if<
     672              :             is_match<S0, S1>::value, bool>::type
     673              :     {
     674            8 :         return decode_compare(s0, s1) >= 0;
     675              :     }
     676              : #endif
     677              : 
     678              :     /** Format the string with percent-decoding applied to the output stream
     679              : 
     680              :         This hidden friend function serializes the decoded view
     681              :         to the output stream.
     682              : 
     683              :         @return A reference to the output stream, for chaining
     684              : 
     685              :         @param os The output stream to write to
     686              : 
     687              :         @param s The decoded view to write
     688              :     */
     689              :     friend
     690              :     std::ostream&
     691            2 :     operator<<(
     692              :         std::ostream& os,
     693              :         decode_view const& s)
     694              :     {
     695              :         // hidden friend
     696            2 :         s.write(os);
     697            2 :         return os;
     698              :     }
     699              : 
     700              : private:
     701              :     BOOST_URL_DECL
     702              :     void
     703              :     write(std::ostream& os) const;
     704              : };
     705              : 
     706              : /** Format the string with percent-decoding applied to the output stream
     707              : 
     708              :     This function serializes the decoded view
     709              :     to the output stream.
     710              : 
     711              :     @return A reference to the output stream, for chaining
     712              : 
     713              :     @param os The output stream to write to
     714              : 
     715              :     @param s The decoded view to write
     716              : */
     717              : inline
     718              : std::ostream&
     719              : operator<<(
     720              :     std::ostream& os,
     721              :     decode_view const& s);
     722              : 
     723              : //------------------------------------------------
     724              : 
     725              : inline
     726              : decode_view
     727         3697 : pct_string_view::operator*() const noexcept
     728              : {
     729         3697 :     return decode_view(*this);
     730              : }
     731              : 
     732              : #ifndef BOOST_URL_DOCS
     733              : namespace detail {
     734              : template<class... Args>
     735              : decode_view
     736              : make_decode_view(
     737              :     Args&&... args) noexcept
     738              : {
     739              :     return decode_view(
     740              :         std::forward<Args>(args)...);
     741              : }
     742              : } // detail
     743              : #endif
     744              : 
     745              : //------------------------------------------------
     746              : 
     747              : } // urls
     748              : } // boost
     749              : 
     750              : #include <boost/url/impl/decode_view.hpp>
     751              : 
     752              : #endif
        

Generated by: LCOV version 2.1