Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.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_DETAIL_IMPL_FORMAT_ARGS_HPP | ||
11 | #define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP | ||
12 | |||
13 | namespace boost { | ||
14 | namespace urls { | ||
15 | namespace detail { | ||
16 | |||
17 | template< | ||
18 | class A, | ||
19 | typename std::enable_if< | ||
20 | !std::is_integral< | ||
21 | typename std::decay<A>::type>::value, | ||
22 | int>::type = 0> | ||
23 | std::size_t | ||
24 | 286 | get_uvalue( A&& ) | |
25 | { | ||
26 | 286 | return 0; | |
27 | } | ||
28 | |||
29 | template< | ||
30 | class A, | ||
31 | typename std::enable_if< | ||
32 | std::is_integral< | ||
33 | typename std::decay<A>::type>::value && | ||
34 | std::is_signed< | ||
35 | typename std::decay<A>::type>::value, | ||
36 | int>::type = 0> | ||
37 | std::size_t | ||
38 | 94 | get_uvalue( A&& a ) | |
39 | { | ||
40 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 2 times.
|
94 | if (a > 0) |
41 | 90 | return static_cast<std::size_t>(a); | |
42 | 4 | return 0; | |
43 | } | ||
44 | |||
45 | template< | ||
46 | class A, | ||
47 | typename std::enable_if< | ||
48 | std::is_integral< | ||
49 | typename std::decay<A>::type>::value && | ||
50 | std::is_unsigned< | ||
51 | typename std::decay<A>::type>::value, | ||
52 | int>::type = 0> | ||
53 | std::size_t | ||
54 | 28 | get_uvalue( A&& a ) | |
55 | { | ||
56 | 28 | return static_cast<std::size_t>(a); | |
57 | } | ||
58 | |||
59 | BOOST_URL_DECL | ||
60 | std::size_t | ||
61 | get_uvalue( core::string_view a ); | ||
62 | |||
63 | BOOST_URL_DECL | ||
64 | std::size_t | ||
65 | get_uvalue( char a ); | ||
66 | |||
67 | template<class A> | ||
68 | 484 | format_arg:: | |
69 | format_arg( A&& a ) | ||
70 | : arg_( &a ) | ||
71 | , measure_( &measure_impl<A> ) | ||
72 | , fmt_( &format_impl<A> ) | ||
73 | 484 | , value_( get_uvalue(std::forward<A>(a) )) | |
74 | 484 | , ignore_( std::is_same<A, ignore_format>::value ) | |
75 | 484 | {} | |
76 | |||
77 | template<class A> | ||
78 | 37 | format_arg:: | |
79 | format_arg( named_arg<A>&& a ) | ||
80 | 37 | : arg_( &a.value ) | |
81 | , measure_( &measure_impl<A> ) | ||
82 | , fmt_( &format_impl<A> ) | ||
83 | , name_( a.name ) | ||
84 | 37 | , value_( get_uvalue(a.value)) | |
85 | 37 | {} | |
86 | |||
87 | template<class A> | ||
88 | 22 | format_arg:: | |
89 | format_arg( core::string_view name, A&& a ) | ||
90 | : arg_( &a ) | ||
91 | , measure_( &measure_impl<A> ) | ||
92 | , fmt_( &format_impl<A> ) | ||
93 | , name_( name ) | ||
94 | 22 | , value_( get_uvalue(a) ) | |
95 | 22 | {} | |
96 | |||
97 | // define the type-erased implementations that | ||
98 | // depends on everything: the context types, | ||
99 | // formatters, and type erased args | ||
100 | template <class A> | ||
101 | void | ||
102 | 477 | format_arg:: | |
103 | measure_impl( | ||
104 | format_parse_context& pctx, | ||
105 | measure_context& mctx, | ||
106 | grammar::lut_chars const& cs, | ||
107 | void const* a ) | ||
108 | { | ||
109 | using ref_t = typename std::remove_cv< | ||
110 | typename std::remove_reference<A>::type>::type; | ||
111 | 477 | A const& ref = *static_cast<ref_t*>( | |
112 | const_cast<void*>( a ) ); | ||
113 | 470 | formatter<ref_t> f; | |
114 |
2/2✓ Branch 1 taken 238 times.
✓ Branch 2 taken 2 times.
|
477 | pctx.advance_to( f.parse(pctx) ); |
115 |
2/3✓ Branch 1 taken 112 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
473 | mctx.advance_to( f.measure( ref, mctx, cs ) ); |
116 | 473 | } | |
117 | |||
118 | template <class A> | ||
119 | void | ||
120 | 469 | format_arg:: | |
121 | format_impl( | ||
122 | format_parse_context& pctx, | ||
123 | format_context& fctx, | ||
124 | grammar::lut_chars const& cs, | ||
125 | void const* a ) | ||
126 | { | ||
127 | using ref_t = typename std::remove_cv< | ||
128 | typename std::remove_reference<A>::type>::type; | ||
129 | 469 | A const& ref = *static_cast<ref_t*>( | |
130 | const_cast<void*>( a ) ); | ||
131 | 462 | formatter<ref_t> f; | |
132 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
469 | pctx.advance_to( f.parse(pctx) ); |
133 |
2/3✓ Branch 1 taken 112 times.
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
|
469 | fctx.advance_to( f.format( ref, fctx, cs ) ); |
134 | 469 | } | |
135 | |||
136 | // We point to formatter<ignore_format> where | ||
137 | // the format_arg variant would store monostate | ||
138 | template <> | ||
139 | struct formatter<ignore_format> | ||
140 | { | ||
141 | public: | ||
142 | char const* | ||
143 | 6 | parse(format_parse_context& ctx) const | |
144 | { | ||
145 | 6 | return parse_empty_spec( | |
146 | 6 | ctx.begin(), ctx.end()); | |
147 | } | ||
148 | |||
149 | std::size_t | ||
150 | 3 | measure( | |
151 | ignore_format, | ||
152 | measure_context& ctx, | ||
153 | grammar::lut_chars const&) const | ||
154 | { | ||
155 | 3 | return ctx.out(); | |
156 | } | ||
157 | |||
158 | char* | ||
159 | 3 | format( | |
160 | ignore_format, | ||
161 | format_context& ctx, | ||
162 | grammar::lut_chars const&) const | ||
163 | { | ||
164 | 3 | return ctx.out(); | |
165 | } | ||
166 | |||
167 | // We ignore the modifiers in all replacements | ||
168 | // for now | ||
169 | static | ||
170 | char const* | ||
171 | 10 | parse_empty_spec( | |
172 | char const* it, | ||
173 | char const* end) | ||
174 | { | ||
175 | // [it, end] -> "} suffix" | ||
176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | BOOST_ASSERT(it != end); |
177 | ignore_unused(end); | ||
178 | // Should be always empty/valid as an | ||
179 | // implementation detail | ||
180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | BOOST_ASSERT(*it == '}'); |
181 | /* | ||
182 | if (*it != '}') | ||
183 | urls::detail::throw_invalid_argument(); | ||
184 | */ | ||
185 | 10 | return it; | |
186 | } | ||
187 | }; | ||
188 | |||
189 | inline | ||
190 | std::size_t | ||
191 | 625 | measure_one( | |
192 | char c, | ||
193 | grammar::lut_chars const& unreserved) | ||
194 | { | ||
195 | // '%' must be reserved | ||
196 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 625 times.
|
625 | BOOST_ASSERT(! unreserved('%')); |
197 | 625 | return 1 + !unreserved(c) * 2; | |
198 | } | ||
199 | |||
200 | inline | ||
201 | void | ||
202 | 1394 | encode_one( | |
203 | char*& out, | ||
204 | char c, | ||
205 | grammar::lut_chars const& unreserved) | ||
206 | { | ||
207 | // '%' must be reserved | ||
208 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1394 times.
|
1394 | BOOST_ASSERT(! unreserved('%')); |
209 |
2/2✓ Branch 1 taken 1378 times.
✓ Branch 2 taken 16 times.
|
1394 | if(unreserved(c)) |
210 | { | ||
211 | 1378 | *out++ = c; | |
212 | 1378 | return; | |
213 | } | ||
214 | 16 | *out++ = '%'; | |
215 | 16 | *out++ = urls::detail::hexdigs[0][c>>4]; | |
216 | 16 | *out++ = urls::detail::hexdigs[0][c&0xf]; | |
217 | } | ||
218 | |||
219 | // get an unsigned value from format_args | ||
220 | BOOST_URL_DECL | ||
221 | void | ||
222 | get_width_from_args( | ||
223 | std::size_t arg_idx, | ||
224 | core::string_view arg_name, | ||
225 | format_args args, | ||
226 | std::size_t& w); | ||
227 | |||
228 | // formatter for string view | ||
229 | template <> | ||
230 | struct formatter<core::string_view> | ||
231 | { | ||
232 | private: | ||
233 | char fill = ' '; | ||
234 | char align = '\0'; | ||
235 | std::size_t width = 0; | ||
236 | std::size_t width_idx = std::size_t(-1); | ||
237 | core::string_view width_name; | ||
238 | |||
239 | public: | ||
240 | BOOST_URL_DECL | ||
241 | char const* | ||
242 | parse(format_parse_context& ctx); | ||
243 | |||
244 | BOOST_URL_DECL | ||
245 | std::size_t | ||
246 | measure( | ||
247 | core::string_view str, | ||
248 | measure_context& ctx, | ||
249 | grammar::lut_chars const& cs) const; | ||
250 | |||
251 | BOOST_URL_DECL | ||
252 | char* | ||
253 | format( | ||
254 | core::string_view str, | ||
255 | format_context& ctx, | ||
256 | grammar::lut_chars const& cs) const; | ||
257 | }; | ||
258 | |||
259 | // formatter for anything convertible to a | ||
260 | // string view | ||
261 | template <class T> | ||
262 | struct formatter< | ||
263 | T, typename std::enable_if< | ||
264 | std::is_convertible< | ||
265 | T, core::string_view>::value>::type> | ||
266 | { | ||
267 | formatter<core::string_view> impl_; | ||
268 | |||
269 | public: | ||
270 | char const* | ||
271 | 480 | parse(format_parse_context& ctx) | |
272 | { | ||
273 | 480 | return impl_.parse(ctx); | |
274 | } | ||
275 | |||
276 | std::size_t | ||
277 | 242 | measure( | |
278 | core::string_view str, | ||
279 | measure_context& ctx, | ||
280 | grammar::lut_chars const& cs) const | ||
281 | { | ||
282 | 242 | return impl_.measure(str, ctx, cs); | |
283 | } | ||
284 | |||
285 | char* | ||
286 | 238 | format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const | |
287 | { | ||
288 | 238 | return impl_.format(str, ctx, cs); | |
289 | } | ||
290 | }; | ||
291 | |||
292 | template <> | ||
293 | struct formatter<char> | ||
294 | { | ||
295 | formatter<core::string_view> impl_; | ||
296 | |||
297 | public: | ||
298 | char const* | ||
299 | 129 | parse(format_parse_context& ctx) | |
300 | { | ||
301 | 129 | return impl_.parse(ctx); | |
302 | } | ||
303 | |||
304 | std::size_t | ||
305 | 64 | measure( | |
306 | char c, | ||
307 | measure_context& ctx, | ||
308 | grammar::lut_chars const& cs) const | ||
309 | { | ||
310 |
1/2✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | return impl_.measure({&c, 1}, ctx, cs); |
311 | } | ||
312 | |||
313 | char* | ||
314 | 64 | format( | |
315 | char c, | ||
316 | format_context& ctx, | ||
317 | grammar::lut_chars const& cs) const | ||
318 | { | ||
319 |
1/2✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | return impl_.format({&c, 1}, ctx, cs); |
320 | } | ||
321 | }; | ||
322 | |||
323 | // formatters for a single integer | ||
324 | class integer_formatter_impl | ||
325 | { | ||
326 | char fill = ' '; | ||
327 | char align = '\0'; | ||
328 | char sign = '-'; | ||
329 | bool zeros = false; | ||
330 | std::size_t width = 0; | ||
331 | std::size_t width_idx = std::size_t(-1); | ||
332 | core::string_view width_name; | ||
333 | |||
334 | public: | ||
335 | BOOST_URL_DECL | ||
336 | char const* | ||
337 | parse(format_parse_context& ctx); | ||
338 | |||
339 | BOOST_URL_DECL | ||
340 | std::size_t | ||
341 | measure( | ||
342 | unsigned long long int v, | ||
343 | measure_context& ctx, | ||
344 | grammar::lut_chars const& cs) const; | ||
345 | |||
346 | BOOST_URL_DECL | ||
347 | std::size_t | ||
348 | measure( | ||
349 | long long int v, | ||
350 | measure_context& ctx, | ||
351 | grammar::lut_chars const& cs) const; | ||
352 | |||
353 | BOOST_URL_DECL | ||
354 | char* | ||
355 | format( | ||
356 | unsigned long long int v, | ||
357 | format_context& ctx, | ||
358 | grammar::lut_chars const& cs) const; | ||
359 | |||
360 | BOOST_URL_DECL | ||
361 | char* | ||
362 | format( | ||
363 | long long int v, | ||
364 | format_context& ctx, | ||
365 | grammar::lut_chars const& cs) const; | ||
366 | }; | ||
367 | |||
368 | template <class T> | ||
369 | struct formatter< | ||
370 | T, typename std::enable_if< | ||
371 | mp11::mp_contains<mp11::mp_list< | ||
372 | short int, | ||
373 | int, | ||
374 | long int, | ||
375 | long long int, | ||
376 | unsigned short int, | ||
377 | unsigned int, | ||
378 | unsigned long int, | ||
379 | unsigned long long int>, T>::value>::type> | ||
380 | { | ||
381 | private: | ||
382 | integer_formatter_impl impl_; | ||
383 | using base_value_type = typename std::conditional< | ||
384 | std::is_unsigned<T>::value, | ||
385 | unsigned long long int, | ||
386 | long long int | ||
387 | >::type; | ||
388 | |||
389 | public: | ||
390 | char const* | ||
391 | 186 | parse(format_parse_context& ctx) | |
392 | { | ||
393 | 186 | return impl_.parse(ctx); | |
394 | } | ||
395 | |||
396 | std::size_t | ||
397 | 92 | measure( | |
398 | T v, | ||
399 | measure_context& ctx, | ||
400 | grammar::lut_chars const& cs) const | ||
401 | { | ||
402 | return impl_.measure( | ||
403 | 92 | static_cast<base_value_type>(v), ctx, cs); | |
404 | } | ||
405 | |||
406 | char* | ||
407 | 48 | format(T v, format_context& ctx, grammar::lut_chars const& cs) const | |
408 | { | ||
409 | return impl_.format( | ||
410 | 48 | static_cast<base_value_type>(v), ctx, cs); | |
411 | } | ||
412 | }; | ||
413 | |||
414 | } // detail | ||
415 | } // url | ||
416 | } // boost | ||
417 | |||
418 | #endif | ||
419 |