GCC Code Coverage Report


Directory: libs/url/
File: include/boost/url/grammar/string_token.hpp
Date: 2025-11-10 19:06:22
Exec Total Coverage
Lines: 42 43 97.7%
Functions: 16 16 100.0%
Branches: 3 4 75.0%

Line Branch Exec Source
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 6860 virtual ~arg() = default;
77
78 /// Default constructor
79 3430 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 3086 prepare(std::size_t n) override
252 {
253 3086 s_.resize(n);
254 3086 return &s_[0];
255 }
256
257 result_type
258 3086 result() noexcept
259 {
260 3086 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 3 append_to_t(
294 string_type& s) noexcept
295 3 : s_(s)
296 {
297 3 }
298
299 char*
300 3 prepare(std::size_t n) override
301 {
302 3 std::size_t n0 = s_.size();
303
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if(n > s_.max_size() - n0)
304 urls::detail::throw_length_error();
305 3 s_.resize(n0 + n);
306 3 return &s_[n0];
307 }
308
309 result_type
310 3 result() noexcept
311 {
312 3 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 3 append_to(
337 std::basic_string<
338 char,
339 std::char_traits<char>,
340 Alloc>& s)
341 {
342 3 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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
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
486