LCOV - code coverage report
Current view: top level - url/grammar - string_token.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 97.7 % 43 42 1
Test Date: 2026-02-25 21:00:01 Functions: 94.1 % 17 16 1

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot 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_GRAMMAR_STRING_TOKEN_HPP
      11                 : #define BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
      12                 : 
      13                 : #include <boost/url/detail/config.hpp>
      14                 : #include <boost/core/detail/string_view.hpp>
      15                 : #include <boost/url/detail/except.hpp>
      16                 : #include <memory>
      17                 : #include <string>
      18                 : 
      19                 : namespace boost {
      20                 : namespace urls {
      21                 : namespace string_token {
      22                 : 
      23                 : /** Base class for string tokens, and algorithm parameters
      24                 : 
      25                 :     This abstract interface provides a means
      26                 :     for an algorithm to generically obtain a
      27                 :     modifiable, contiguous character buffer
      28                 :     of prescribed size.
      29                 : 
      30                 :     A @ref StringToken should be derived
      31                 :     from this class. As the author of an
      32                 :     algorithm using a @ref StringToken,
      33                 :     simply declare an rvalue reference
      34                 :     as a parameter type.
      35                 : 
      36                 :     Instances of this type are intended only
      37                 :     to be used once and then destroyed.
      38                 : 
      39                 :     @par Example
      40                 :     The declared function accepts any
      41                 :     temporary instance of `arg` to be
      42                 :     used for writing:
      43                 :     @code
      44                 :     void algorithm( string_token::arg&& dest );
      45                 :     @endcode
      46                 : 
      47                 :     To implement the interface for your type
      48                 :     or use-case, derive from the class and
      49                 :     implement the prepare function.
      50                 : */
      51                 : struct arg
      52                 : {
      53                 :     /** Return a modifiable character buffer
      54                 : 
      55                 :         This function attempts to obtain a
      56                 :         character buffer with space for at
      57                 :         least `n` characters. Upon success,
      58                 :         a pointer to the beginning of the
      59                 :         buffer is returned. Ownership is not
      60                 :         transferred; the caller should not
      61                 :         attempt to free the storage. The
      62                 :         buffer shall remain valid until
      63                 :         `this` is destroyed.
      64                 : 
      65                 :         @note
      66                 :         This function may only be called once.
      67                 :         After invoking the function, the only
      68                 :         valid operation is destruction.
      69                 : 
      70                 :         @param n The number of characters needed
      71                 :         @return A pointer to the buffer
      72                 :     */
      73                 :     virtual char* prepare(std::size_t n) = 0;
      74                 : 
      75                 :     /// Virtual destructor
      76 HIT        3689 :     virtual ~arg() = default;
      77                 : 
      78                 :     /// Default constructor
      79            3689 :     arg() = default;
      80                 : 
      81                 :     /// Default move constructor
      82                 :     arg(arg&&) = default;
      83                 : 
      84                 :     /// Deleted copy constructor
      85                 :     arg(arg const&) = delete;
      86                 : 
      87                 :     /// Deleted move assignment
      88                 :     arg& operator=(arg&&) = delete;
      89                 : 
      90                 :     /// Deleted copy assignment
      91                 :     arg& operator=(arg const&) = delete;
      92                 : };
      93                 : 
      94                 : //------------------------------------------------
      95                 : 
      96                 : namespace implementation_defined {
      97                 : template<class T, class = void>
      98                 : struct is_token : std::false_type {};
      99                 : 
     100                 : template<class T>
     101                 : struct is_token<T, void_t<
     102                 :     decltype(std::declval<T&>().prepare(
     103                 :         std::declval<std::size_t>())),
     104                 :     decltype(std::declval<T&>().result())
     105                 :     > > : std::integral_constant<bool,
     106                 :         std::is_convertible<decltype(
     107                 :             std::declval<T&>().result()),
     108                 :             typename T::result_type>::value &&
     109                 :         std::is_same<decltype(
     110                 :             std::declval<T&>().prepare(0)),
     111                 :             char*>::value &&
     112                 :         std::is_base_of<arg, T>::value &&
     113                 :         std::is_convertible<T const volatile*,
     114                 :             arg const volatile*>::value
     115                 :     >
     116                 : {
     117                 : };
     118                 : } // implementation_defined
     119                 : 
     120                 : /** Trait to determine if a type is a string token
     121                 : 
     122                 :     This trait returns `true` if `T` is a valid
     123                 :     @ref StringToken type, and `false` otherwise.
     124                 : 
     125                 :     @par Example
     126                 :     @code
     127                 :     static_assert( string_token::is_token<T>::value );
     128                 :     @endcode
     129                 :  */
     130                 : template<class T>
     131                 : using is_token = implementation_defined::is_token<T>;
     132                 : 
     133                 : #ifdef BOOST_URL_HAS_CONCEPTS
     134                 : /** Concept for a string token
     135                 : 
     136                 :     This concept is satisfied if `T` is a
     137                 :     valid string token type.
     138                 : 
     139                 :     A string token is an rvalue passed to a function template
     140                 :     which customizes the return type of the function and also
     141                 :     controls how a modifiable character buffer is obtained and presented.
     142                 : 
     143                 :     The string token's lifetime extends only for the duration of the
     144                 :     function call in which it appears as a parameter.
     145                 : 
     146                 :     A string token cannot be copied, moved, or assigned, and must be
     147                 :     destroyed when the function returns or throws.
     148                 : 
     149                 :     @par Semantics
     150                 : 
     151                 :     `T::result_type` determines the return type of functions
     152                 :     that accept a string token.
     153                 : 
     154                 :     The `prepare()` function overrides the virtual function
     155                 :     in the base class @ref arg. It must return a pointer to
     156                 :     a character buffer of at least size `n`, otherwise
     157                 :     throw an exception. This function is called only
     158                 :     once or not at all.
     159                 : 
     160                 :     The `result()` function is invoked by the algorithm
     161                 :     to receive the result from the string token.
     162                 :     It is only invoked if `prepare()` returned
     163                 :     successfully and the string token was not destroyed.
     164                 :     It is only called after `prepare()` returns
     165                 :     successfully, and the string token is destroyed
     166                 :     when the algorithm completes or if an exception
     167                 :     is thrown.
     168                 : 
     169                 :     String tokens cannot be reused.
     170                 : 
     171                 :     @par Exemplars
     172                 :     String token prototype:
     173                 : 
     174                 :     @code
     175                 :     struct StringToken : string_token::arg
     176                 :     {
     177                 :         using result_type = std::string;
     178                 : 
     179                 :         char* prepare( std::size_t n ) override;
     180                 : 
     181                 :         result_type result();
     182                 :     };
     183                 :     @endcode
     184                 : 
     185                 :     Algorithm prototype:
     186                 : 
     187                 :     @code
     188                 :     namespace detail {
     189                 : 
     190                 :     // Algorithm implementation may be placed
     191                 :     // out of line, and written as an ordinary
     192                 :     // function (no template required).
     193                 :     void algorithm_impl( string_token::arg& token )
     194                 :     {
     195                 :         std::size_t n = 0;
     196                 : 
     197                 :         // calculate space needed in n
     198                 :         // ...
     199                 : 
     200                 :         // acquire a destination buffer
     201                 :         char* dest = token.prepare( n );
     202                 : 
     203                 :         // write the characters to the buffer
     204                 :     }
     205                 :     } // detail
     206                 : 
     207                 :     // public interface is a function template,
     208                 :     // defaulting to return std::string.
     209                 :     template< class StringToken = string_token::return_string >
     210                 :     auto
     211                 :     algorithm( StringToken&& token = {} ) ->
     212                 :         typename StringToken::result_type
     213                 :     {
     214                 :         // invoke the algorithm with the token
     215                 :         algorithm_impl( token );
     216                 : 
     217                 :         // return the result from the token
     218                 :         return token.result();
     219                 :     }
     220                 :     @endcode
     221                 : 
     222                 :     @par Models
     223                 :     The following classes and functions implement and
     224                 :     generate string tokens.
     225                 : 
     226                 :     @li @ref return_string
     227                 :     @li @ref assign_to
     228                 :     @li @ref preserve_size
     229                 : 
     230                 :  */
     231                 : template <class T>
     232                 : concept StringToken =
     233                 :     std::derived_from<T, string_token::arg> &&
     234                 :     requires (T t, std::size_t n)
     235                 : {
     236                 :     typename T::result_type;
     237                 :     { t.prepare(n) } -> std::same_as<char*>;
     238                 :     { t.result() } -> std::convertible_to<typename T::result_type>;
     239                 : };
     240                 : #endif
     241                 : 
     242                 : //------------------------------------------------
     243                 : 
     244                 : namespace implementation_defined {
     245                 : struct return_string
     246                 :     : arg
     247                 : {
     248                 :     using result_type = std::string;
     249                 : 
     250                 :     char*
     251            3341 :     prepare(std::size_t n) override
     252                 :     {
     253            3341 :         s_.resize(n);
     254            3341 :         return &s_[0];
     255                 :     }
     256                 : 
     257                 :     result_type
     258            3341 :     result() noexcept
     259                 :     {
     260            3341 :         return std::move(s_);
     261                 :     }
     262                 : 
     263                 : private:
     264                 :     result_type s_;
     265                 : };
     266                 : } // implementation_defined
     267                 : 
     268                 : /** A string token for returning a plain string
     269                 : 
     270                 :     This @ref StringToken is used to customize
     271                 :     a function to return a plain string.
     272                 : 
     273                 :     This is default token type used by
     274                 :     the methods of @ref url_view_base
     275                 :     that return decoded strings.
     276                 :  */
     277                 : using return_string = implementation_defined::return_string;
     278                 : 
     279                 : //------------------------------------------------
     280                 : 
     281                 : namespace implementation_defined {
     282                 : template<class Alloc>
     283                 : struct append_to_t
     284                 :     : arg
     285                 : {
     286                 :     using string_type = std::basic_string<
     287                 :         char, std::char_traits<char>,
     288                 :             Alloc>;
     289                 : 
     290                 :     using result_type = string_type&;
     291                 : 
     292                 :     explicit
     293               6 :     append_to_t(
     294                 :         string_type& s) noexcept
     295               6 :         : s_(s)
     296                 :     {
     297               6 :     }
     298                 : 
     299                 :     char*
     300               6 :     prepare(std::size_t n) override
     301                 :     {
     302               6 :         std::size_t n0 = s_.size();
     303               6 :         if(n > s_.max_size() - n0)
     304 MIS           0 :             urls::detail::throw_length_error();
     305 HIT           6 :         s_.resize(n0 + n);
     306               6 :         return &s_[n0];
     307                 :     }
     308                 : 
     309                 :     result_type
     310               6 :     result() noexcept
     311                 :     {
     312               6 :         return s_;
     313                 :     }
     314                 : 
     315                 : private:
     316                 :     string_type& s_;
     317                 : };
     318                 : } // implementation_defined
     319                 : 
     320                 : /** Create a string token for appending to a plain string
     321                 : 
     322                 :     This function creates a @ref StringToken
     323                 :     which appends to an existing plain string.
     324                 : 
     325                 :     Functions using this token will append
     326                 :     the result to the existing string and
     327                 :     return a reference to it.
     328                 : 
     329                 :     @param s The string to append
     330                 :     @return A string token
     331                 :  */
     332                 : template<
     333                 :     class Alloc =
     334                 :         std::allocator<char>>
     335                 : implementation_defined::append_to_t<Alloc>
     336               6 : append_to(
     337                 :     std::basic_string<
     338                 :         char,
     339                 :         std::char_traits<char>,
     340                 :         Alloc>& s)
     341                 : {
     342               6 :     return implementation_defined::append_to_t<Alloc>(s);
     343                 : }
     344                 : 
     345                 : //------------------------------------------------
     346                 : 
     347                 : namespace implementation_defined {
     348                 : template<class Alloc>
     349                 : struct assign_to_t
     350                 :     : arg
     351                 : {
     352                 :     using string_type = std::basic_string<
     353                 :         char, std::char_traits<char>,
     354                 :             Alloc>;
     355                 : 
     356                 :     using result_type = string_type&;
     357                 : 
     358                 :     explicit
     359             337 :     assign_to_t(
     360                 :         string_type& s) noexcept
     361             337 :         : s_(s)
     362                 :     {
     363             337 :     }
     364                 : 
     365                 :     char*
     366             337 :     prepare(std::size_t n) override
     367                 :     {
     368             337 :         s_.resize(n);
     369             337 :         return &s_[0];
     370                 :     }
     371                 : 
     372                 :     result_type
     373             337 :     result() noexcept
     374                 :     {
     375             337 :         return s_;
     376                 :     }
     377                 : 
     378                 : private:
     379                 :     string_type& s_;
     380                 : };
     381                 : } // implementation_defined
     382                 : 
     383                 : /** Create a string token for assigning to a plain string
     384                 : 
     385                 :     This function creates a @ref StringToken
     386                 :     which assigns to an existing plain string.
     387                 : 
     388                 :     Functions using this token will assign
     389                 :     the result to the existing string and
     390                 :     return a reference to it.
     391                 : 
     392                 :     @param s The string to assign
     393                 :     @return A string token
     394                 :  */
     395                 : template<
     396                 :     class Alloc =
     397                 :         std::allocator<char>>
     398                 : implementation_defined::assign_to_t<Alloc>
     399             337 : assign_to(
     400                 :     std::basic_string<
     401                 :         char,
     402                 :         std::char_traits<char>,
     403                 :         Alloc>& s)
     404                 : {
     405             337 :     return implementation_defined::assign_to_t<Alloc>(s);
     406                 : }
     407                 : 
     408                 : //------------------------------------------------
     409                 : 
     410                 : namespace implementation_defined {
     411                 : template<class Alloc>
     412                 : struct preserve_size_t
     413                 :     : arg
     414                 : {
     415                 :     using result_type = core::string_view;
     416                 : 
     417                 :     using string_type = std::basic_string<
     418                 :         char, std::char_traits<char>,
     419                 :             Alloc>;
     420                 : 
     421                 :     explicit
     422               4 :     preserve_size_t(
     423                 :         string_type& s) noexcept
     424               4 :         : s_(s)
     425                 :     {
     426               4 :     }
     427                 : 
     428                 :     char*
     429               4 :     prepare(std::size_t n) override
     430                 :     {
     431               4 :         n_ = n;
     432                 :         // preserve size() to
     433                 :         // avoid value-init
     434               4 :         if(s_.size() < n)
     435               2 :             s_.resize(n);
     436               4 :         return &s_[0];
     437                 :     }
     438                 : 
     439                 :     result_type
     440               4 :     result() noexcept
     441                 :     {
     442               4 :         return core::string_view(
     443               8 :             s_.data(), n_);
     444                 :     }
     445                 : 
     446                 : private:
     447                 :     string_type& s_;
     448                 :     std::size_t n_ = 0;
     449                 : };
     450                 : } // implementation_defined
     451                 : 
     452                 : /** Create a string token for a durable core::string_view
     453                 : 
     454                 :     This function creates a @ref StringToken
     455                 :     which assigns to an existing plain string.
     456                 : 
     457                 :     Functions using this token will assign
     458                 :     the result to the existing string and
     459                 :     return a `core::string_view` to it.
     460                 : 
     461                 :     @param s The string to preserve
     462                 :     @return A string token
     463                 :  */
     464                 : template<
     465                 :     class Alloc =
     466                 :         std::allocator<char>>
     467                 : implementation_defined::preserve_size_t<Alloc>
     468               4 : preserve_size(
     469                 :     std::basic_string<
     470                 :         char,
     471                 :         std::char_traits<char>,
     472                 :         Alloc>& s)
     473                 : {
     474               4 :     return implementation_defined::preserve_size_t<Alloc>(s);
     475                 : }
     476                 : } // string_token
     477                 : 
     478                 : namespace grammar {
     479                 : namespace string_token = ::boost::urls::string_token;
     480                 : } // grammar
     481                 : 
     482                 : } // urls
     483                 : } // boost
     484                 : 
     485                 : #endif
        

Generated by: LCOV version 2.3