LCOV - code coverage report
Current view: top level - boost/url/grammar/string_token.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.7 % 43 42
Test Date: 2025-01-10 18:07:09 Functions: 94.1 % 17 16

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

Generated by: LCOV version 2.1