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. As the author of an | ||
29 | algorithm simply declare an rvalue | ||
30 | reference as a parameter type. | ||
31 | |||
32 | <br> | ||
33 | |||
34 | Instances of this type are intended only | ||
35 | to be used once and then destroyed. | ||
36 | |||
37 | @par Example | ||
38 | The declared function accepts any | ||
39 | temporary instance of `arg` to be | ||
40 | used for writing: | ||
41 | @code | ||
42 | void algorithm( string_token::arg&& dest ); | ||
43 | @endcode | ||
44 | |||
45 | To implement the interface for your type | ||
46 | or use-case, derive from the class and | ||
47 | implement the prepare function. | ||
48 | */ | ||
49 | struct arg | ||
50 | { | ||
51 | /** Return a modifiable character buffer | ||
52 | |||
53 | This function attempts to obtain a | ||
54 | character buffer with space for at | ||
55 | least `n` characters. Upon success, | ||
56 | a pointer to the beginning of the | ||
57 | buffer is returned. Ownership is not | ||
58 | transferred; the caller should not | ||
59 | attempt to free the storage. The | ||
60 | buffer shall remain valid until | ||
61 | `this` is destroyed. | ||
62 | |||
63 | @note | ||
64 | This function may only be called once. | ||
65 | After invoking the function, the only | ||
66 | valid operation is destruction. | ||
67 | */ | ||
68 | virtual char* prepare(std::size_t n) = 0; | ||
69 | |||
70 | /// Virtual destructor | ||
71 | 6744 | virtual ~arg() = default; | |
72 | |||
73 | /// Default constructor | ||
74 | 3372 | arg() = default; | |
75 | |||
76 | /// Default move constructor | ||
77 | arg(arg&&) = default; | ||
78 | |||
79 | /// Deleted copy constructor | ||
80 | arg(arg const&) = delete; | ||
81 | |||
82 | /// Deleted move assignment | ||
83 | arg& operator=(arg&&) = delete; | ||
84 | |||
85 | /// Deleted copy assignment | ||
86 | arg& operator=(arg const&) = delete; | ||
87 | }; | ||
88 | |||
89 | //------------------------------------------------ | ||
90 | |||
91 | /** Metafunction returning true if T is a StringToken | ||
92 | */ | ||
93 | #ifdef BOOST_URL_DOCS | ||
94 | template<class T> | ||
95 | using is_token = __see_below__; | ||
96 | #else | ||
97 | namespace see_below { | ||
98 | /** Metafunction returning true if T is a StringToken | ||
99 | */ | ||
100 | template<class T, class = void> | ||
101 | struct is_token : std::false_type {}; | ||
102 | |||
103 | /** Metafunction returning true if T is a StringToken | ||
104 | */ | ||
105 | template<class T> | ||
106 | struct is_token<T, void_t< | ||
107 | decltype(std::declval<T&>().prepare( | ||
108 | std::declval<std::size_t>())), | ||
109 | decltype(std::declval<T&>().result()) | ||
110 | > > : std::integral_constant<bool, | ||
111 | std::is_convertible<decltype( | ||
112 | std::declval<T&>().result()), | ||
113 | typename T::result_type>::value && | ||
114 | std::is_same<decltype( | ||
115 | std::declval<T&>().prepare(0)), | ||
116 | char*>::value && | ||
117 | std::is_base_of<arg, T>::value && | ||
118 | std::is_convertible<T const volatile*, | ||
119 | arg const volatile*>::value | ||
120 | > | ||
121 | { | ||
122 | }; | ||
123 | } // see_below | ||
124 | |||
125 | /** Metafunction returning true if T is a StringToken | ||
126 | */ | ||
127 | template<class T> | ||
128 | using is_token = see_below::is_token<T>; | ||
129 | #endif | ||
130 | |||
131 | //------------------------------------------------ | ||
132 | |||
133 | /** A token for returning a plain string | ||
134 | */ | ||
135 | #ifdef BOOST_URL_DOCS | ||
136 | using return_string = __implementation_defined__; | ||
137 | #else | ||
138 | namespace implementation_defined { | ||
139 | struct return_string | ||
140 | : arg | ||
141 | { | ||
142 | using result_type = std::string; | ||
143 | |||
144 | char* | ||
145 | 3028 | prepare(std::size_t n) override | |
146 | { | ||
147 | 3028 | s_.resize(n); | |
148 | 3028 | return &s_[0]; | |
149 | } | ||
150 | |||
151 | result_type | ||
152 | 3028 | result() noexcept | |
153 | { | ||
154 | 3028 | return std::move(s_); | |
155 | } | ||
156 | |||
157 | private: | ||
158 | result_type s_; | ||
159 | }; | ||
160 | } // implementation_defined | ||
161 | |||
162 | /** A token for returning a plain string | ||
163 | */ | ||
164 | using return_string = implementation_defined::return_string; | ||
165 | #endif | ||
166 | |||
167 | //------------------------------------------------ | ||
168 | |||
169 | /** A token for appending to a plain string | ||
170 | */ | ||
171 | #ifdef BOOST_URL_DOCS | ||
172 | template< | ||
173 | class Allocator = | ||
174 | std::allocator<char>> | ||
175 | __implementation_defined__ | ||
176 | append_to( | ||
177 | std::basic_string< | ||
178 | char, | ||
179 | std::char_traits<char>, | ||
180 | Allocator>& s); | ||
181 | #else | ||
182 | namespace implementation_defined { | ||
183 | template<class Alloc> | ||
184 | struct append_to_t | ||
185 | : arg | ||
186 | { | ||
187 | using string_type = std::basic_string< | ||
188 | char, std::char_traits<char>, | ||
189 | Alloc>; | ||
190 | |||
191 | using result_type = string_type&; | ||
192 | |||
193 | explicit | ||
194 | 3 | append_to_t( | |
195 | string_type& s) noexcept | ||
196 | 3 | : s_(s) | |
197 | { | ||
198 | 3 | } | |
199 | |||
200 | char* | ||
201 | 3 | prepare(std::size_t n) override | |
202 | { | ||
203 | 3 | std::size_t n0 = s_.size(); | |
204 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if(n > s_.max_size() - n0) |
205 | ✗ | urls::detail::throw_length_error(); | |
206 | 3 | s_.resize(n0 + n); | |
207 | 3 | return &s_[n0]; | |
208 | } | ||
209 | |||
210 | result_type | ||
211 | 3 | result() noexcept | |
212 | { | ||
213 | 3 | return s_; | |
214 | } | ||
215 | |||
216 | private: | ||
217 | string_type& s_; | ||
218 | }; | ||
219 | } // implementation_defined | ||
220 | |||
221 | /** Create a token for appending to a plain string | ||
222 | */ | ||
223 | template< | ||
224 | class Alloc = | ||
225 | std::allocator<char>> | ||
226 | implementation_defined::append_to_t<Alloc> | ||
227 | 3 | append_to( | |
228 | std::basic_string< | ||
229 | char, | ||
230 | std::char_traits<char>, | ||
231 | Alloc>& s) | ||
232 | { | ||
233 | 3 | return implementation_defined::append_to_t<Alloc>(s); | |
234 | } | ||
235 | #endif | ||
236 | |||
237 | //------------------------------------------------ | ||
238 | |||
239 | /** A token for assigning to a plain string | ||
240 | */ | ||
241 | #ifdef BOOST_URL_DOCS | ||
242 | template< | ||
243 | class Allocator = | ||
244 | std::allocator<char>> | ||
245 | __implementation_defined__ | ||
246 | assign_to( | ||
247 | std::basic_string< | ||
248 | char, | ||
249 | std::char_traits<char>, | ||
250 | Allocator>& s); | ||
251 | #else | ||
252 | namespace implementation_defined { | ||
253 | template<class Alloc> | ||
254 | struct assign_to_t | ||
255 | : arg | ||
256 | { | ||
257 | using string_type = std::basic_string< | ||
258 | char, std::char_traits<char>, | ||
259 | Alloc>; | ||
260 | |||
261 | using result_type = string_type&; | ||
262 | |||
263 | explicit | ||
264 | 337 | assign_to_t( | |
265 | string_type& s) noexcept | ||
266 | 337 | : s_(s) | |
267 | { | ||
268 | 337 | } | |
269 | |||
270 | char* | ||
271 | 337 | prepare(std::size_t n) override | |
272 | { | ||
273 | 337 | s_.resize(n); | |
274 | 337 | return &s_[0]; | |
275 | } | ||
276 | |||
277 | result_type | ||
278 | 337 | result() noexcept | |
279 | { | ||
280 | 337 | return s_; | |
281 | } | ||
282 | |||
283 | private: | ||
284 | string_type& s_; | ||
285 | }; | ||
286 | } // implementation_defined | ||
287 | |||
288 | /** A token for assigning to a plain string | ||
289 | */ | ||
290 | template< | ||
291 | class Alloc = | ||
292 | std::allocator<char>> | ||
293 | implementation_defined::assign_to_t<Alloc> | ||
294 | 337 | assign_to( | |
295 | std::basic_string< | ||
296 | char, | ||
297 | std::char_traits<char>, | ||
298 | Alloc>& s) | ||
299 | { | ||
300 | 337 | return implementation_defined::assign_to_t<Alloc>(s); | |
301 | } | ||
302 | #endif | ||
303 | |||
304 | //------------------------------------------------ | ||
305 | |||
306 | /** A token for producing a durable core::string_view from a temporary string | ||
307 | */ | ||
308 | #ifdef BOOST_URL_DOCS | ||
309 | template< | ||
310 | class Allocator = | ||
311 | std::allocator<char>> | ||
312 | __implementation_defined__ | ||
313 | preserve_size( | ||
314 | std::basic_string< | ||
315 | char, | ||
316 | std::char_traits<char>, | ||
317 | Allocator>& s); | ||
318 | #else | ||
319 | namespace implementation_defined { | ||
320 | template<class Alloc> | ||
321 | struct preserve_size_t | ||
322 | : arg | ||
323 | { | ||
324 | using result_type = core::string_view; | ||
325 | |||
326 | using string_type = std::basic_string< | ||
327 | char, std::char_traits<char>, | ||
328 | Alloc>; | ||
329 | |||
330 | explicit | ||
331 | 4 | preserve_size_t( | |
332 | string_type& s) noexcept | ||
333 | 4 | : s_(s) | |
334 | { | ||
335 | 4 | } | |
336 | |||
337 | char* | ||
338 | 4 | prepare(std::size_t n) override | |
339 | { | ||
340 | 4 | n_ = n; | |
341 | // preserve size() to | ||
342 | // avoid value-init | ||
343 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(s_.size() < n) |
344 | 2 | s_.resize(n); | |
345 | 4 | return &s_[0]; | |
346 | } | ||
347 | |||
348 | result_type | ||
349 | 4 | result() noexcept | |
350 | { | ||
351 | 4 | return core::string_view( | |
352 | 8 | s_.data(), n_); | |
353 | } | ||
354 | |||
355 | private: | ||
356 | string_type& s_; | ||
357 | std::size_t n_ = 0; | ||
358 | }; | ||
359 | } // implementation_defined | ||
360 | |||
361 | /** A token for producing a durable core::string_view from a temporary string | ||
362 | */ | ||
363 | template< | ||
364 | class Alloc = | ||
365 | std::allocator<char>> | ||
366 | implementation_defined::preserve_size_t<Alloc> | ||
367 | 4 | preserve_size( | |
368 | std::basic_string< | ||
369 | char, | ||
370 | std::char_traits<char>, | ||
371 | Alloc>& s) | ||
372 | { | ||
373 | 4 | return implementation_defined::preserve_size_t<Alloc>(s); | |
374 | } | ||
375 | #endif | ||
376 | |||
377 | } // string_token | ||
378 | |||
379 | namespace grammar { | ||
380 | namespace string_token = ::boost::urls::string_token; | ||
381 | } // grammar | ||
382 | |||
383 | } // urls | ||
384 | } // boost | ||
385 | |||
386 | #endif | ||
387 |