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-07-10 02:48:26 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              :     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         3773 :     decode_view(
     211              :         pct_string_view s,
     212              :         encoding_opts opt = {}) noexcept
     213         3773 :         : decode_view(
     214              :             detail::to_sv(s),
     215              :             s.decoded_size(),
     216         3773 :             opt)
     217              :     {
     218         3773 :     }
     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         3948 :     size() const noexcept
     265              :     {
     266         3948 :         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         2926 :     decode_compare(decode_view s0, S const& s1) noexcept
     565              :     {
     566         2926 :         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         2471 :     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         2471 :         return decode_compare(s0, s1) == 0;
     585              :     }
     586              : 
     587              :     template<class S0, class S1>
     588          739 :     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          739 :         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         3697 : pct_string_view::operator*() const noexcept
     673              : {
     674         3697 :     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 2.1