include/boost/url/detail/impl/format_args.hpp

100.0% Lines (84/84) 100.0% Functions (207/207)
include/boost/url/detail/impl/format_args.hpp
Line TLA Hits Source Code
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 200 get_uvalue( A&& )
25 {
26 200 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 56 get_uvalue( A&& a )
39 {
40 56 if (a > 0)
41 53 return static_cast<std::size_t>(a);
42 3 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 14 get_uvalue( A&& a )
55 {
56 14 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 291 format_arg::
69 format_arg( A&& a )
70 291 : arg_( &a )
71 291 , measure_( &measure_impl<A> )
72 291 , fmt_( &format_impl<A> )
73 291 , value_( get_uvalue(std::forward<A>(a) ))
74 291 , ignore_( std::is_same<A, ignore_format>::value )
75 291 {}
76
77 template<class A>
78 21 format_arg::
79 format_arg( named_arg<A>&& a )
80 21 : arg_( &a.value )
81 21 , measure_( &measure_impl<A> )
82 21 , fmt_( &format_impl<A> )
83 21 , name_( a.name )
84 21 , value_( get_uvalue(a.value))
85 21 {}
86
87 template<class A>
88 26 format_arg::
89 format_arg( core::string_view name, A&& a )
90 26 : arg_( &a )
91 26 , measure_( &measure_impl<A> )
92 26 , fmt_( &format_impl<A> )
93 26 , name_( name )
94 26 , value_( get_uvalue(a) )
95 26 {}
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 290 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 290 A const& ref = *static_cast<ref_t*>(
112 const_cast<void*>( a ) );
113 285 formatter<ref_t> f;
114 290 pctx.advance_to( f.parse(pctx) );
115 288 mctx.advance_to( f.measure( ref, mctx, cs ) );
116 288 }
117
118 template <class A>
119 void
120 286 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 286 A const& ref = *static_cast<ref_t*>(
130 const_cast<void*>( a ) );
131 281 formatter<ref_t> f;
132 286 pctx.advance_to( f.parse(pctx) );
133 286 fctx.advance_to( f.format( ref, fctx, cs ) );
134 286 }
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 10 BOOST_ASSERT(it != end);
177 ignore_unused(end);
178 // Should be always empty/valid as an
179 // implementation detail
180 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 753 measure_one(
192 char c,
193 grammar::lut_chars const& unreserved)
194 {
195 // '%' must be reserved
196 753 BOOST_ASSERT(! unreserved('%'));
197 753 return 1 + !unreserved(c) * 2;
198 }
199
200 inline
201 void
202 1856 encode_one(
203 char*& out,
204 char c,
205 grammar::lut_chars const& unreserved)
206 {
207 // '%' must be reserved
208 1856 BOOST_ASSERT(! unreserved('%'));
209 1856 if(unreserved(c))
210 {
211 1837 *out++ = c;
212 1837 return;
213 }
214 19 *out++ = '%';
215 19 auto uc = static_cast<unsigned char>(c);
216 19 *out++ = urls::detail::hexdigs[0][uc>>4];
217 19 *out++ = urls::detail::hexdigs[0][uc&0xf];
218 }
219
220 // get an unsigned value from format_args
221 BOOST_URL_DECL
222 void
223 get_width_from_args(
224 std::size_t arg_idx,
225 core::string_view arg_name,
226 format_args args,
227 std::size_t& w);
228
229 // formatter for string view
230 template <>
231 struct formatter<core::string_view>
232 {
233 private:
234 char fill = ' ';
235 char align = '\0';
236 std::size_t width = 0;
237 std::size_t width_idx = std::size_t(-1);
238 core::string_view width_name;
239
240 public:
241 BOOST_URL_DECL
242 char const*
243 parse(format_parse_context& ctx);
244
245 BOOST_URL_DECL
246 std::size_t
247 measure(
248 core::string_view str,
249 measure_context& ctx,
250 grammar::lut_chars const& cs) const;
251
252 BOOST_URL_DECL
253 char*
254 format(
255 core::string_view str,
256 format_context& ctx,
257 grammar::lut_chars const& cs) const;
258 };
259
260 // formatter for anything convertible to a
261 // string view
262 template <class T>
263 struct formatter<
264 T, typename std::enable_if<
265 std::is_convertible<
266 T, core::string_view>::value>::type>
267 {
268 formatter<core::string_view> impl_;
269
270 public:
271 char const*
272 322 parse(format_parse_context& ctx)
273 {
274 322 return impl_.parse(ctx);
275 }
276
277 std::size_t
278 162 measure(
279 core::string_view str,
280 measure_context& ctx,
281 grammar::lut_chars const& cs) const
282 {
283 162 return impl_.measure(str, ctx, cs);
284 }
285
286 char*
287 160 format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
288 {
289 160 return impl_.format(str, ctx, cs);
290 }
291 };
292
293 template <>
294 struct formatter<char>
295 {
296 formatter<core::string_view> impl_;
297
298 public:
299 char const*
300 129 parse(format_parse_context& ctx)
301 {
302 129 return impl_.parse(ctx);
303 }
304
305 std::size_t
306 64 measure(
307 char c,
308 measure_context& ctx,
309 grammar::lut_chars const& cs) const
310 {
311 64 return impl_.measure({&c, 1}, ctx, cs);
312 }
313
314 char*
315 64 format(
316 char c,
317 format_context& ctx,
318 grammar::lut_chars const& cs) const
319 {
320 64 return impl_.format({&c, 1}, ctx, cs);
321 }
322 };
323
324 // formatters for a single integer
325 class integer_formatter_impl
326 {
327 char fill = ' ';
328 char align = '\0';
329 char sign = '-';
330 bool zeros = false;
331 std::size_t width = 0;
332 std::size_t width_idx = std::size_t(-1);
333 core::string_view width_name;
334
335 public:
336 BOOST_URL_DECL
337 char const*
338 parse(format_parse_context& ctx);
339
340 BOOST_URL_DECL
341 std::size_t
342 measure(
343 unsigned long long int v,
344 measure_context& ctx,
345 grammar::lut_chars const& cs) const;
346
347 BOOST_URL_DECL
348 std::size_t
349 measure(
350 long long int v,
351 measure_context& ctx,
352 grammar::lut_chars const& cs) const;
353
354 BOOST_URL_DECL
355 char*
356 format(
357 unsigned long long int v,
358 format_context& ctx,
359 grammar::lut_chars const& cs) const;
360
361 BOOST_URL_DECL
362 char*
363 format(
364 long long int v,
365 format_context& ctx,
366 grammar::lut_chars const& cs) const;
367 };
368
369 template <class T>
370 struct formatter<
371 T, typename std::enable_if<
372 mp11::mp_contains<mp11::mp_list<
373 short int,
374 int,
375 long int,
376 long long int,
377 unsigned short int,
378 unsigned int,
379 unsigned long int,
380 unsigned long long int>, T>::value>::type>
381 {
382 private:
383 integer_formatter_impl impl_;
384 using base_value_type = typename std::conditional<
385 std::is_unsigned<T>::value,
386 unsigned long long int,
387 long long int
388 >::type;
389
390 public:
391 char const*
392 115 parse(format_parse_context& ctx)
393 {
394 115 return impl_.parse(ctx);
395 }
396
397 std::size_t
398 57 measure(
399 T v,
400 measure_context& ctx,
401 grammar::lut_chars const& cs) const
402 {
403 57 return impl_.measure(
404 57 static_cast<base_value_type>(v), ctx, cs);
405 }
406
407 char*
408 57 format(T v, format_context& ctx, grammar::lut_chars const& cs) const
409 {
410 57 return impl_.format(
411 57 static_cast<base_value_type>(v), ctx, cs);
412 }
413 };
414
415 } // detail
416 } // url
417 } // boost
418
419 #endif
420