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