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