TLA Line data 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 HIT 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
|