GCC Code Coverage Report


Directory: libs/url/
File: boost/url/detail/impl/format_args.hpp
Date: 2024-08-19 20:08:56
Exec Total Coverage
Lines: 83 83 100.0%
Functions: 202 202 100.0%
Branches: 17 26 65.4%

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 484 : arg_( &a )
71 484 , measure_( &measure_impl<A> )
72 484 , 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 37 , measure_( &measure_impl<A> )
82 37 , fmt_( &format_impl<A> )
83 37 , 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 22 : arg_( &a )
91 22 , measure_( &measure_impl<A> )
92 22 , fmt_( &format_impl<A> )
93 22 , 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 92 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 48 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