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 | // prevent misuse | ||
71 | 6744 | virtual ~arg() = default; | |
72 | 3372 | arg() = default; | |
73 | arg(arg&&) = default; | ||
74 | arg(arg const&) = delete; | ||
75 | arg& operator=(arg&&) = delete; | ||
76 | arg& operator=(arg const&) = delete; | ||
77 | }; | ||
78 | |||
79 | //------------------------------------------------ | ||
80 | |||
81 | /** Metafunction returning true if T is a StringToken | ||
82 | */ | ||
83 | #ifdef BOOST_URL_DOCS | ||
84 | template<class T> | ||
85 | using is_token = __see_below__; | ||
86 | #else | ||
87 | template<class T, class = void> | ||
88 | struct is_token : std::false_type {}; | ||
89 | |||
90 | template<class T> | ||
91 | struct is_token<T, void_t< | ||
92 | decltype(std::declval<T&>().prepare( | ||
93 | std::declval<std::size_t>())), | ||
94 | decltype(std::declval<T&>().result()) | ||
95 | > > : std::integral_constant<bool, | ||
96 | std::is_convertible<decltype( | ||
97 | std::declval<T&>().result()), | ||
98 | typename T::result_type>::value && | ||
99 | std::is_same<decltype( | ||
100 | std::declval<T&>().prepare(0)), | ||
101 | char*>::value && | ||
102 | std::is_base_of<arg, T>::value && | ||
103 | std::is_convertible<T const volatile*, | ||
104 | arg const volatile*>::value | ||
105 | > | ||
106 | { | ||
107 | }; | ||
108 | #endif | ||
109 | |||
110 | //------------------------------------------------ | ||
111 | |||
112 | /** A token for returning a plain string | ||
113 | */ | ||
114 | #ifdef BOOST_URL_DOCS | ||
115 | using return_string = __implementation_defined__; | ||
116 | #else | ||
117 | struct return_string | ||
118 | : arg | ||
119 | { | ||
120 | using result_type = std::string; | ||
121 | |||
122 | char* | ||
123 | 3028 | prepare(std::size_t n) override | |
124 | { | ||
125 | 3028 | s_.resize(n); | |
126 | 3028 | return &s_[0]; | |
127 | } | ||
128 | |||
129 | result_type | ||
130 | 3028 | result() noexcept | |
131 | { | ||
132 | 3028 | return std::move(s_); | |
133 | } | ||
134 | |||
135 | private: | ||
136 | result_type s_; | ||
137 | }; | ||
138 | #endif | ||
139 | |||
140 | //------------------------------------------------ | ||
141 | |||
142 | /** A token for appending to a plain string | ||
143 | */ | ||
144 | #ifdef BOOST_URL_DOCS | ||
145 | template< | ||
146 | class Allocator = | ||
147 | std::allocator<char>> | ||
148 | __implementation_defined__ | ||
149 | append_to( | ||
150 | std::basic_string< | ||
151 | char, | ||
152 | std::char_traits<char>, | ||
153 | Allocator>& s); | ||
154 | #else | ||
155 | template<class Alloc> | ||
156 | struct append_to_t | ||
157 | : arg | ||
158 | { | ||
159 | using string_type = std::basic_string< | ||
160 | char, std::char_traits<char>, | ||
161 | Alloc>; | ||
162 | |||
163 | using result_type = string_type&; | ||
164 | |||
165 | explicit | ||
166 | 3 | append_to_t( | |
167 | string_type& s) noexcept | ||
168 | 3 | : s_(s) | |
169 | { | ||
170 | 3 | } | |
171 | |||
172 | char* | ||
173 | 3 | prepare(std::size_t n) override | |
174 | { | ||
175 | 3 | std::size_t n0 = s_.size(); | |
176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if(n > s_.max_size() - n0) |
177 | ✗ | urls::detail::throw_length_error(); | |
178 | 3 | s_.resize(n0 + n); | |
179 | 3 | return &s_[n0]; | |
180 | } | ||
181 | |||
182 | result_type | ||
183 | 3 | result() noexcept | |
184 | { | ||
185 | 3 | return s_; | |
186 | } | ||
187 | |||
188 | private: | ||
189 | string_type& s_; | ||
190 | }; | ||
191 | |||
192 | template< | ||
193 | class Alloc = | ||
194 | std::allocator<char>> | ||
195 | append_to_t<Alloc> | ||
196 | 3 | append_to( | |
197 | std::basic_string< | ||
198 | char, | ||
199 | std::char_traits<char>, | ||
200 | Alloc>& s) | ||
201 | { | ||
202 | 3 | return append_to_t<Alloc>(s); | |
203 | } | ||
204 | #endif | ||
205 | |||
206 | //------------------------------------------------ | ||
207 | |||
208 | /** A token for assigning to a plain string | ||
209 | */ | ||
210 | #ifdef BOOST_URL_DOCS | ||
211 | template< | ||
212 | class Allocator = | ||
213 | std::allocator<char>> | ||
214 | __implementation_defined__ | ||
215 | assign_to( | ||
216 | std::basic_string< | ||
217 | char, | ||
218 | std::char_traits<char>, | ||
219 | Allocator>& s); | ||
220 | #else | ||
221 | template<class Alloc> | ||
222 | struct assign_to_t | ||
223 | : arg | ||
224 | { | ||
225 | using string_type = std::basic_string< | ||
226 | char, std::char_traits<char>, | ||
227 | Alloc>; | ||
228 | |||
229 | using result_type = string_type&; | ||
230 | |||
231 | explicit | ||
232 | 337 | assign_to_t( | |
233 | string_type& s) noexcept | ||
234 | 337 | : s_(s) | |
235 | { | ||
236 | 337 | } | |
237 | |||
238 | char* | ||
239 | 337 | prepare(std::size_t n) override | |
240 | { | ||
241 | 337 | s_.resize(n); | |
242 | 337 | return &s_[0]; | |
243 | } | ||
244 | |||
245 | result_type | ||
246 | 337 | result() noexcept | |
247 | { | ||
248 | 337 | return s_; | |
249 | } | ||
250 | |||
251 | private: | ||
252 | string_type& s_; | ||
253 | }; | ||
254 | |||
255 | template< | ||
256 | class Alloc = | ||
257 | std::allocator<char>> | ||
258 | assign_to_t<Alloc> | ||
259 | 337 | assign_to( | |
260 | std::basic_string< | ||
261 | char, | ||
262 | std::char_traits<char>, | ||
263 | Alloc>& s) | ||
264 | { | ||
265 | 337 | return assign_to_t<Alloc>(s); | |
266 | } | ||
267 | #endif | ||
268 | |||
269 | //------------------------------------------------ | ||
270 | |||
271 | /** A token for producing a durable core::string_view from a temporary string | ||
272 | */ | ||
273 | #ifdef BOOST_URL_DOCS | ||
274 | template< | ||
275 | class Allocator = | ||
276 | std::allocator<char>> | ||
277 | __implementation_defined__ | ||
278 | preserve_size( | ||
279 | std::basic_string< | ||
280 | char, | ||
281 | std::char_traits<char>, | ||
282 | Allocator>& s); | ||
283 | #else | ||
284 | template<class Alloc> | ||
285 | struct preserve_size_t | ||
286 | : arg | ||
287 | { | ||
288 | using result_type = core::string_view; | ||
289 | |||
290 | using string_type = std::basic_string< | ||
291 | char, std::char_traits<char>, | ||
292 | Alloc>; | ||
293 | |||
294 | explicit | ||
295 | 4 | preserve_size_t( | |
296 | string_type& s) noexcept | ||
297 | 4 | : s_(s) | |
298 | { | ||
299 | 4 | } | |
300 | |||
301 | char* | ||
302 | 4 | prepare(std::size_t n) override | |
303 | { | ||
304 | 4 | n_ = n; | |
305 | // preserve size() to | ||
306 | // avoid value-init | ||
307 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(s_.size() < n) |
308 | 2 | s_.resize(n); | |
309 | 4 | return &s_[0]; | |
310 | } | ||
311 | |||
312 | result_type | ||
313 | 4 | result() noexcept | |
314 | { | ||
315 | 4 | return core::string_view( | |
316 | 8 | s_.data(), n_); | |
317 | } | ||
318 | |||
319 | private: | ||
320 | string_type& s_; | ||
321 | std::size_t n_ = 0; | ||
322 | }; | ||
323 | |||
324 | template< | ||
325 | class Alloc = | ||
326 | std::allocator<char>> | ||
327 | preserve_size_t<Alloc> | ||
328 | 4 | preserve_size( | |
329 | std::basic_string< | ||
330 | char, | ||
331 | std::char_traits<char>, | ||
332 | Alloc>& s) | ||
333 | { | ||
334 | 4 | return preserve_size_t<Alloc>(s); | |
335 | } | ||
336 | #endif | ||
337 | |||
338 | } // string_token | ||
339 | |||
340 | namespace grammar { | ||
341 | namespace string_token = ::boost::urls::string_token; | ||
342 | } // grammar | ||
343 | |||
344 | } // urls | ||
345 | } // boost | ||
346 | |||
347 | #endif | ||
348 |