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 160 : get_uvalue( A&& )
25 : {
26 160 : 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 47 : get_uvalue( A&& a )
39 : {
40 47 : if (a > 0)
41 45 : return static_cast<std::size_t>(a);
42 2 : 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 259 : format_arg::
69 : format_arg( A&& a )
70 259 : : arg_( &a )
71 259 : , measure_( &measure_impl<A> )
72 259 : , fmt_( &format_impl<A> )
73 259 : , value_( get_uvalue(std::forward<A>(a) ))
74 259 : , ignore_( std::is_same<A, ignore_format>::value )
75 259 : {}
76 :
77 : template<class A>
78 19 : format_arg::
79 : format_arg( named_arg<A>&& a )
80 19 : : arg_( &a.value )
81 19 : , measure_( &measure_impl<A> )
82 19 : , fmt_( &format_impl<A> )
83 19 : , name_( a.name )
84 19 : , value_( get_uvalue(a.value))
85 19 : {}
86 :
87 : template<class A>
88 11 : format_arg::
89 : format_arg( core::string_view name, A&& a )
90 11 : : arg_( &a )
91 11 : , measure_( &measure_impl<A> )
92 11 : , fmt_( &format_impl<A> )
93 11 : , name_( name )
94 11 : , value_( get_uvalue(a) )
95 11 : {}
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 240 : 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 240 : A const& ref = *static_cast<ref_t*>(
112 : const_cast<void*>( a ) );
113 235 : formatter<ref_t> f;
114 240 : pctx.advance_to( f.parse(pctx) );
115 238 : mctx.advance_to( f.measure( ref, mctx, cs ) );
116 238 : }
117 :
118 : template <class A>
119 : void
120 236 : 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 236 : A const& ref = *static_cast<ref_t*>(
130 : const_cast<void*>( a ) );
131 231 : formatter<ref_t> f;
132 236 : pctx.advance_to( f.parse(pctx) );
133 236 : fctx.advance_to( f.format( ref, fctx, cs ) );
134 236 : }
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 625 : measure_one(
192 : char c,
193 : grammar::lut_chars const& unreserved)
194 : {
195 : // '%' must be reserved
196 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 1394 : BOOST_ASSERT(! unreserved('%'));
209 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 240 : parse(format_parse_context& ctx)
272 : {
273 240 : return impl_.parse(ctx);
274 : }
275 :
276 : std::size_t
277 121 : measure(
278 : core::string_view str,
279 : measure_context& ctx,
280 : grammar::lut_chars const& cs) const
281 : {
282 121 : return impl_.measure(str, ctx, cs);
283 : }
284 :
285 : char*
286 119 : format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
287 : {
288 119 : 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 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 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 97 : parse(format_parse_context& ctx)
392 : {
393 97 : return impl_.parse(ctx);
394 : }
395 :
396 : std::size_t
397 48 : measure(
398 : T v,
399 : measure_context& ctx,
400 : grammar::lut_chars const& cs) const
401 : {
402 48 : return impl_.measure(
403 48 : 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
|