Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-31 08:57:57

0001 //
0002 // Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/url
0008 //
0009 
0010 #ifndef BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
0011 #define BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
0012 
0013 #include <boost/url/detail/config.hpp>
0014 #include <boost/core/detail/string_view.hpp>
0015 #include <boost/url/detail/except.hpp>
0016 #include <memory>
0017 #include <string>
0018 
0019 namespace boost {
0020 namespace urls {
0021 namespace string_token {
0022 
0023 /** Base class for string tokens, and algorithm parameters
0024 
0025     This abstract interface provides a means
0026     for an algorithm to generically obtain a
0027     modifiable, contiguous character buffer
0028     of prescribed size.
0029 
0030     A @ref StringToken should be derived
0031     from this class. As the author of an
0032     algorithm using a @ref StringToken,
0033     simply declare an rvalue reference
0034     as a parameter type.
0035 
0036     Instances of this type are intended only
0037     to be used once and then destroyed.
0038 
0039     @par Example
0040     The declared function accepts any
0041     temporary instance of `arg` to be
0042     used for writing:
0043     @code
0044     void algorithm( string_token::arg&& dest );
0045     @endcode
0046 
0047     To implement the interface for your type
0048     or use-case, derive from the class and
0049     implement the prepare function.
0050 */
0051 struct arg
0052 {
0053     /** Return a modifiable character buffer
0054 
0055         This function attempts to obtain a
0056         character buffer with space for at
0057         least `n` characters. Upon success,
0058         a pointer to the beginning of the
0059         buffer is returned. Ownership is not
0060         transferred; the caller should not
0061         attempt to free the storage. The
0062         buffer shall remain valid until
0063         `this` is destroyed.
0064 
0065         @note
0066         This function may only be called once.
0067         After invoking the function, the only
0068         valid operation is destruction.
0069 
0070         @param n The number of characters needed
0071         @return A pointer to the buffer
0072     */
0073     virtual char* prepare(std::size_t n) = 0;
0074 
0075     /// Virtual destructor
0076     virtual ~arg() = default;
0077 
0078     /// Default constructor
0079     arg() = default;
0080 
0081     /// Default move constructor
0082     arg(arg&&) = default;
0083 
0084     /// Deleted copy constructor
0085     arg(arg const&) = delete;
0086 
0087     /// Deleted move assignment
0088     arg& operator=(arg&&) = delete;
0089 
0090     /// Deleted copy assignment
0091     arg& operator=(arg const&) = delete;
0092 };
0093 
0094 //------------------------------------------------
0095 
0096 namespace implementation_defined {
0097 template<class T, class = void>
0098 struct is_token : std::false_type {};
0099 
0100 template<class T>
0101 struct is_token<T, void_t<
0102     decltype(std::declval<T&>().prepare(
0103         std::declval<std::size_t>())),
0104     decltype(std::declval<T&>().result())
0105     > > : std::integral_constant<bool,
0106         std::is_convertible<decltype(
0107             std::declval<T&>().result()),
0108             typename T::result_type>::value &&
0109         std::is_same<decltype(
0110             std::declval<T&>().prepare(0)),
0111             char*>::value &&
0112         std::is_base_of<arg, T>::value &&
0113         std::is_convertible<T const volatile*,
0114             arg const volatile*>::value
0115     >
0116 {
0117 };
0118 } // implementation_defined
0119 
0120 /** Trait to determine if a type is a string token
0121 
0122     This trait returns `true` if `T` is a valid
0123     @ref StringToken type, and `false` otherwise.
0124 
0125     @par Example
0126     @code
0127     static_assert( string_token::is_token<T>::value );
0128     @endcode
0129  */
0130 template<class T>
0131 using is_token = implementation_defined::is_token<T>;
0132 
0133 #ifdef BOOST_URL_HAS_CONCEPTS
0134 /** Concept for a string token
0135 
0136     This concept is satisfied if `T` is a
0137     valid string token type.
0138 
0139     A string token is an rvalue passed to a function template
0140     which customizes the return type of the function and also
0141     controls how a modifiable character buffer is obtained and presented.
0142 
0143     The string token's lifetime extends only for the duration of the
0144     function call in which it appears as a parameter.
0145 
0146     A string token cannot be copied, moved, or assigned, and must be
0147     destroyed when the function returns or throws.
0148 
0149     @par Semantics
0150 
0151     `T::result_type` determines the return type of functions
0152     that accept a string token.
0153 
0154     The `prepare()` function overrides the virtual function
0155     in the base class @ref arg. It must return a pointer to
0156     a character buffer of at least size `n`, otherwise
0157     throw an exception. This function is called only
0158     once or not at all.
0159 
0160     The `result()` function is invoked by the algorithm
0161     to receive the result from the string token.
0162     It is only invoked if `prepare()` returned
0163     successfully and the string token was not destroyed.
0164     It is only called after `prepare()` returns
0165     successfully, and the string token is destroyed
0166     when the algorithm completes or if an exception
0167     is thrown.
0168 
0169     String tokens cannot be reused.
0170 
0171     @par Exemplars
0172     String token prototype:
0173 
0174     @code
0175     struct StringToken : string_token::arg
0176     {
0177         using result_type = std::string;
0178 
0179         char* prepare( std::size_t n ) override;
0180 
0181         result_type result();
0182     };
0183     @endcode
0184 
0185     Algorithm prototype:
0186 
0187     @code
0188     namespace detail {
0189 
0190     // Algorithm implementation may be placed
0191     // out of line, and written as an ordinary
0192     // function (no template required).
0193     void algorithm_impl( string_token::arg& token )
0194     {
0195         std::size_t n = 0;
0196 
0197         // calculate space needed in n
0198         // ...
0199 
0200         // acquire a destination buffer
0201         char* dest = token.prepare( n );
0202 
0203         // write the characters to the buffer
0204     }
0205     } // detail
0206 
0207     // public interface is a function template,
0208     // defaulting to return std::string.
0209     template< class StringToken = string_token::return_string >
0210     auto
0211     algorithm( StringToken&& token = {} ) ->
0212         typename StringToken::result_type
0213     {
0214         // invoke the algorithm with the token
0215         algorithm_impl( token );
0216 
0217         // return the result from the token
0218         return token.result();
0219     }
0220     @endcode
0221 
0222     @par Models
0223     The following classes and functions implement and
0224     generate string tokens.
0225 
0226     @li @ref return_string
0227     @li @ref assign_to
0228     @li @ref preserve_size
0229 
0230  */
0231 template <class T>
0232 concept StringToken =
0233     std::derived_from<T, string_token::arg> &&
0234     requires (T t, std::size_t n)
0235 {
0236     typename T::result_type;
0237     { t.prepare(n) } -> std::same_as<char*>;
0238     { t.result() } -> std::convertible_to<typename T::result_type>;
0239 };
0240 #endif
0241 
0242 //------------------------------------------------
0243 
0244 namespace implementation_defined {
0245 struct return_string
0246     : arg
0247 {
0248     using result_type = std::string;
0249 
0250     char*
0251     prepare(std::size_t n) override
0252     {
0253         s_.resize(n);
0254         return &s_[0];
0255     }
0256 
0257     result_type
0258     result() noexcept
0259     {
0260         return std::move(s_);
0261     }
0262 
0263 private:
0264     result_type s_;
0265 };
0266 } // implementation_defined
0267 
0268 /** A string token for returning a plain string
0269 
0270     This @ref StringToken is used to customize
0271     a function to return a plain string.
0272 
0273     This is default token type used by
0274     the methods of @ref url_view_base
0275     that return decoded strings.
0276  */
0277 using return_string = implementation_defined::return_string;
0278 
0279 //------------------------------------------------
0280 
0281 namespace implementation_defined {
0282 template<class Alloc>
0283 struct append_to_t
0284     : arg
0285 {
0286     using string_type = std::basic_string<
0287         char, std::char_traits<char>,
0288             Alloc>;
0289 
0290     using result_type = string_type&;
0291 
0292     explicit
0293     append_to_t(
0294         string_type& s) noexcept
0295         : s_(s)
0296     {
0297     }
0298 
0299     char*
0300     prepare(std::size_t n) override
0301     {
0302         std::size_t n0 = s_.size();
0303         if(n > s_.max_size() - n0)
0304             urls::detail::throw_length_error();
0305         s_.resize(n0 + n);
0306         return &s_[n0];
0307     }
0308 
0309     result_type
0310     result() noexcept
0311     {
0312         return s_;
0313     }
0314 
0315 private:
0316     string_type& s_;
0317 };
0318 } // implementation_defined
0319 
0320 /** Create a string token for appending to a plain string
0321 
0322     This function creates a @ref StringToken
0323     which appends to an existing plain string.
0324 
0325     Functions using this token will append
0326     the result to the existing string and
0327     return a reference to it.
0328 
0329     @param s The string to append
0330     @return A string token
0331  */
0332 template<
0333     class Alloc =
0334         std::allocator<char>>
0335 implementation_defined::append_to_t<Alloc>
0336 append_to(
0337     std::basic_string<
0338         char,
0339         std::char_traits<char>,
0340         Alloc>& s)
0341 {
0342     return implementation_defined::append_to_t<Alloc>(s);
0343 }
0344 
0345 //------------------------------------------------
0346 
0347 namespace implementation_defined {
0348 template<class Alloc>
0349 struct assign_to_t
0350     : arg
0351 {
0352     using string_type = std::basic_string<
0353         char, std::char_traits<char>,
0354             Alloc>;
0355 
0356     using result_type = string_type&;
0357 
0358     explicit
0359     assign_to_t(
0360         string_type& s) noexcept
0361         : s_(s)
0362     {
0363     }
0364 
0365     char*
0366     prepare(std::size_t n) override
0367     {
0368         s_.resize(n);
0369         return &s_[0];
0370     }
0371 
0372     result_type
0373     result() noexcept
0374     {
0375         return s_;
0376     }
0377 
0378 private:
0379     string_type& s_;
0380 };
0381 } // implementation_defined
0382 
0383 /** Create a string token for assigning to a plain string
0384 
0385     This function creates a @ref StringToken
0386     which assigns to an existing plain string.
0387 
0388     Functions using this token will assign
0389     the result to the existing string and
0390     return a reference to it.
0391 
0392     @param s The string to assign
0393     @return A string token
0394  */
0395 template<
0396     class Alloc =
0397         std::allocator<char>>
0398 implementation_defined::assign_to_t<Alloc>
0399 assign_to(
0400     std::basic_string<
0401         char,
0402         std::char_traits<char>,
0403         Alloc>& s)
0404 {
0405     return implementation_defined::assign_to_t<Alloc>(s);
0406 }
0407 
0408 //------------------------------------------------
0409 
0410 namespace implementation_defined {
0411 template<class Alloc>
0412 struct preserve_size_t
0413     : arg
0414 {
0415     using result_type = core::string_view;
0416 
0417     using string_type = std::basic_string<
0418         char, std::char_traits<char>,
0419             Alloc>;
0420 
0421     explicit
0422     preserve_size_t(
0423         string_type& s) noexcept
0424         : s_(s)
0425     {
0426     }
0427 
0428     char*
0429     prepare(std::size_t n) override
0430     {
0431         n_ = n;
0432         // preserve size() to
0433         // avoid value-init
0434         if(s_.size() < n)
0435             s_.resize(n);
0436         return &s_[0];
0437     }
0438 
0439     result_type
0440     result() noexcept
0441     {
0442         return core::string_view(
0443             s_.data(), n_);
0444     }
0445 
0446 private:
0447     string_type& s_;
0448     std::size_t n_ = 0;
0449 };
0450 } // implementation_defined
0451 
0452 /** Create a string token for a durable core::string_view
0453 
0454     This function creates a @ref StringToken
0455     which assigns to an existing plain string.
0456 
0457     Functions using this token will assign
0458     the result to the existing string and
0459     return a `core::string_view` to it.
0460 
0461     @param s The string to preserve
0462     @return A string token
0463  */
0464 template<
0465     class Alloc =
0466         std::allocator<char>>
0467 implementation_defined::preserve_size_t<Alloc>
0468 preserve_size(
0469     std::basic_string<
0470         char,
0471         std::char_traits<char>,
0472         Alloc>& s)
0473 {
0474     return implementation_defined::preserve_size_t<Alloc>(s);
0475 }
0476 } // string_token
0477 
0478 namespace grammar {
0479 namespace string_token = ::boost::urls::string_token;
0480 } // grammar
0481 
0482 } // urls
0483 } // boost
0484 
0485 #endif