100.00% Lines (302/302) 100.00% Functions (11/11)
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   10  
11   #include <boost/url/detail/config.hpp> 11   #include <boost/url/detail/config.hpp>
12   #include <boost/url/encode.hpp> 12   #include <boost/url/encode.hpp>
13   #include <boost/url/detail/format_args.hpp> 13   #include <boost/url/detail/format_args.hpp>
14   #include "boost/url/detail/replacement_field_rule.hpp" 14   #include "boost/url/detail/replacement_field_rule.hpp"
15   #include <boost/url/grammar/delim_rule.hpp> 15   #include <boost/url/grammar/delim_rule.hpp>
16   #include <boost/url/grammar/optional_rule.hpp> 16   #include <boost/url/grammar/optional_rule.hpp>
17   #include <boost/url/grammar/parse.hpp> 17   #include <boost/url/grammar/parse.hpp>
18   #include <boost/url/grammar/tuple_rule.hpp> 18   #include <boost/url/grammar/tuple_rule.hpp>
19   #include <boost/url/grammar/unsigned_rule.hpp> 19   #include <boost/url/grammar/unsigned_rule.hpp>
20   20  
21   namespace boost { 21   namespace boost {
22   namespace urls { 22   namespace urls {
23   namespace detail { 23   namespace detail {
24   24  
25   std::size_t 25   std::size_t
HITCBC 26   68 get_uvalue( core::string_view a ) 26   68 get_uvalue( core::string_view a )
27   { 27   {
HITCBC 28   68 core::string_view str(a); 28   68 core::string_view str(a);
HITCBC 29   68 auto rv = grammar::parse( 29   68 auto rv = grammar::parse(
HITCBC 30   68 str, grammar::unsigned_rule<std::size_t>{}); 30   68 str, grammar::unsigned_rule<std::size_t>{});
HITCBC 31   68 if (rv) 31   68 if (rv)
HITCBC 32   2 return *rv; 32   2 return *rv;
HITCBC 33   66 return 0; 33   66 return 0;
34   } 34   }
35   35  
36   std::size_t 36   std::size_t
HITCBC 37   68 get_uvalue( char a ) 37   68 get_uvalue( char a )
38   { 38   {
HITCBC 39   68 core::string_view str(&a, 1); 39   68 core::string_view str(&a, 1);
HITCBC 40   136 return get_uvalue(str); 40   136 return get_uvalue(str);
41   } 41   }
42   42  
43   char const* 43   char const*
HITCBC 44   451 formatter<core::string_view>:: 44   451 formatter<core::string_view>::
45   parse(format_parse_context& ctx) 45   parse(format_parse_context& ctx)
46   { 46   {
HITCBC 47   451 char const* it = ctx.begin(); 47   451 char const* it = ctx.begin();
HITCBC 48   451 char const* end = ctx.end(); 48   451 char const* end = ctx.end();
HITCBC 49   451 BOOST_ASSERT(it != end); 49   451 BOOST_ASSERT(it != end);
50   50  
51   // fill / align 51   // fill / align
HITCBC 52   451 if (end - it > 2) 52   451 if (end - it > 2)
53   { 53   {
HITCBC 54   121 if (*it != '{' && 54   121 if (*it != '{' &&
HITCBC 55   121 *it != '}' && 55   121 *it != '}' &&
HITCBC 56   23 (*(it + 1) == '<' || 56   23 (*(it + 1) == '<' ||
HITCBC 57   21 *(it + 1) == '>' || 57   21 *(it + 1) == '>' ||
HITCBC 58   9 *(it + 1) == '^')) 58   9 *(it + 1) == '^'))
59   { 59   {
HITCBC 60   18 fill = *it; 60   18 fill = *it;
HITCBC 61   18 align = *(it + 1); 61   18 align = *(it + 1);
HITCBC 62   18 it += 2; 62   18 it += 2;
63   } 63   }
64   } 64   }
65   65  
66   // align 66   // align
HITCBC 67   451 if (align == '\0' && 67   451 if (align == '\0' &&
HITCBC 68   433 (*it == '<' || 68   433 (*it == '<' ||
HITCBC 69   433 *it == '>' || 69   433 *it == '>' ||
HITCBC 70   433 *it == '^')) 70   433 *it == '^'))
71   { 71   {
HITCBC 72   4 align = *it++; 72   4 align = *it++;
73   } 73   }
74   74  
75   // width 75   // width
HITCBC 76   451 char const* it0 = it; 76   451 char const* it0 = it;
HITCBC 77   451 constexpr auto width_rule = 77   451 constexpr auto width_rule =
78   grammar::variant_rule( 78   grammar::variant_rule(
79   grammar::unsigned_rule<std::size_t>{}, 79   grammar::unsigned_rule<std::size_t>{},
80   grammar::tuple_rule( 80   grammar::tuple_rule(
81   grammar::squelch( 81   grammar::squelch(
82   grammar::delim_rule('{')), 82   grammar::delim_rule('{')),
83   grammar::optional_rule( 83   grammar::optional_rule(
84   arg_id_rule), 84   arg_id_rule),
85   grammar::squelch( 85   grammar::squelch(
86   grammar::delim_rule('}')))); 86   grammar::delim_rule('}'))));
HITCBC 87   451 auto rw = grammar::parse(it, end, width_rule); 87   451 auto rw = grammar::parse(it, end, width_rule);
HITCBC 88   451 if (!rw) 88   451 if (!rw)
89   { 89   {
90   // rewind 90   // rewind
HITCBC 91   429 it = it0; 91   429 it = it0;
92   } 92   }
HITCBC 93   22 else if (align != '\0') 93   22 else if (align != '\0')
94   { 94   {
95   // width is ignored when align is '\0' 95   // width is ignored when align is '\0'
HITCBC 96   22 if (rw->index() == 0) 96   22 if (rw->index() == 0)
97   { 97   {
98   // unsigned_rule 98   // unsigned_rule
HITCBC 99   12 width = variant2::get<0>(*rw); 99   12 width = variant2::get<0>(*rw);
100   } 100   }
101   else 101   else
102   { 102   {
103   // arg_id: store the id idx or string 103   // arg_id: store the id idx or string
HITCBC 104   10 auto& arg_id = variant2::get<1>(*rw); 104   10 auto& arg_id = variant2::get<1>(*rw);
HITCBC 105   10 if (!arg_id) 105   10 if (!arg_id)
106   { 106   {
107   // empty arg_id, use and consume 107   // empty arg_id, use and consume
108   // the next arg idx 108   // the next arg idx
HITCBC 109   2 width_idx = ctx.next_arg_id(); 109   2 width_idx = ctx.next_arg_id();
110   } 110   }
HITCBC 111   8 else if (arg_id->index() == 0) 111   8 else if (arg_id->index() == 0)
112   { 112   {
113   // string identifier 113   // string identifier
HITCBC 114   4 width_name = variant2::get<0>(*arg_id); 114   4 width_name = variant2::get<0>(*arg_id);
115   } 115   }
116   else 116   else
117   { 117   {
118   // integer identifier: use the 118   // integer identifier: use the
119   // idx of this format_arg 119   // idx of this format_arg
HITCBC 120   4 width_idx = variant2::get<1>(*arg_id); 120   4 width_idx = variant2::get<1>(*arg_id);
121   } 121   }
122   } 122   }
123   } 123   }
124   124  
125   // type is parsed but doesn't have to 125   // type is parsed but doesn't have to
126   // be stored for strings 126   // be stored for strings
HITCBC 127   451 if (*it == 'c' || 127   451 if (*it == 'c' ||
HITCBC 128   448 *it == 's') 128   448 *it == 's')
129   { 129   {
HITCBC 130   25 ++it; 130   25 ++it;
131   } 131   }
132   132  
133   // we should have arrived at the end now 133   // we should have arrived at the end now
HITCBC 134   451 if (*it != '}') 134   451 if (*it != '}')
135   { 135   {
HITCBC 136   1 urls::detail::throw_invalid_argument(); 136   1 urls::detail::throw_invalid_argument();
137   } 137   }
138   138  
HITCBC 139   450 return it; 139   450 return it;
140   } 140   }
141   141  
142   std::size_t 142   std::size_t
HITCBC 143   226 formatter<core::string_view>:: 143   226 formatter<core::string_view>::
144   measure( 144   measure(
145   core::string_view str, 145   core::string_view str,
146   measure_context& ctx, 146   measure_context& ctx,
147   grammar::lut_chars const& cs) const 147   grammar::lut_chars const& cs) const
148   { 148   {
HITCBC 149   226 std::size_t w = width; 149   226 std::size_t w = width;
HITCBC 150   449 if (width_idx != std::size_t(-1) || 150   449 if (width_idx != std::size_t(-1) ||
HITCBC 151   223 !width_name.empty()) 151   223 !width_name.empty())
152   { 152   {
HITCBC 153   5 get_width_from_args( 153   5 get_width_from_args(
HITCBC 154   5 width_idx, width_name, ctx.args(), w); 154   5 width_idx, width_name, ctx.args(), w);
155   } 155   }
156   156  
HITCBC 157   226 std::size_t n = ctx.out(); 157   226 std::size_t n = ctx.out();
HITCBC 158   226 if (str.size() < w) 158   226 if (str.size() < w)
HITCBC 159   10 n += measure_one(fill, cs) * (w - str.size()); 159   10 n += measure_one(fill, cs) * (w - str.size());
160   160  
HITCBC 161   226 return n + encoded_size(str, cs); 161   226 return n + encoded_size(str, cs);
162   } 162   }
163   163  
164   char* 164   char*
HITCBC 165   224 formatter<core::string_view>:: 165   224 formatter<core::string_view>::
166   format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const 166   format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
167   { 167   {
HITCBC 168   224 std::size_t w = width; 168   224 std::size_t w = width;
HITCBC 169   445 if (width_idx != std::size_t(-1) || 169   445 if (width_idx != std::size_t(-1) ||
HITCBC 170   221 !width_name.empty()) 170   221 !width_name.empty())
171   { 171   {
HITCBC 172   5 get_width_from_args( 172   5 get_width_from_args(
HITCBC 173   5 width_idx, width_name, ctx.args(), w); 173   5 width_idx, width_name, ctx.args(), w);
174   } 174   }
175   175  
HITCBC 176   224 std::size_t lpad = 0; 176   224 std::size_t lpad = 0;
HITCBC 177   224 std::size_t rpad = 0; 177   224 std::size_t rpad = 0;
HITCBC 178   224 if (str.size() < w) 178   224 if (str.size() < w)
179   { 179   {
HITCBC 180   10 std::size_t pad = w - str.size(); 180   10 std::size_t pad = w - str.size();
HITCBC 181   10 switch (align) 181   10 switch (align)
182   { 182   {
HITCBC 183   1 case '<': 183   1 case '<':
HITCBC 184   1 rpad = pad; 184   1 rpad = pad;
HITCBC 185   1 break; 185   1 break;
HITCBC 186   6 case '>': 186   6 case '>':
HITCBC 187   6 lpad = pad; 187   6 lpad = pad;
HITCBC 188   6 break; 188   6 break;
HITCBC 189   3 case '^': 189   3 case '^':
HITCBC 190   3 lpad = pad / 2; 190   3 lpad = pad / 2;
HITCBC 191   3 rpad = pad - lpad; 191   3 rpad = pad - lpad;
HITCBC 192   3 break; 192   3 break;
193   } 193   }
194   } 194   }
195   195  
196   // unsafe `encode`, assuming `out` has 196   // unsafe `encode`, assuming `out` has
197   // enough capacity 197   // enough capacity
HITCBC 198   224 char* out = ctx.out(); 198   224 char* out = ctx.out();
HITCBC 199   252 for (std::size_t i = 0; i < lpad; ++i) 199   252 for (std::size_t i = 0; i < lpad; ++i)
HITCBC 200   28 encode_one(out, fill, cs); 200   28 encode_one(out, fill, cs);
HITCBC 201   1252 for (char c: str) 201   1252 for (char c: str)
HITCBC 202   1028 encode_one(out, c, cs); 202   1028 encode_one(out, c, cs);
HITCBC 203   232 for (std::size_t i = 0; i < rpad; ++i) 203   232 for (std::size_t i = 0; i < rpad; ++i)
HITCBC 204   8 encode_one(out, fill, cs); 204   8 encode_one(out, fill, cs);
HITCBC 205   224 return out; 205   224 return out;
206   } 206   }
207   207  
208   void 208   void
HITCBC 209   28 get_width_from_args( 209   28 get_width_from_args(
210   std::size_t arg_idx, 210   std::size_t arg_idx,
211   core::string_view arg_name, 211   core::string_view arg_name,
212   format_args args, 212   format_args args,
213   std::size_t& w) 213   std::size_t& w)
214   { 214   {
215   // check arg_id 215   // check arg_id
HITCBC 216   28 format_arg warg; 216   28 format_arg warg;
HITCBC 217   28 if (arg_idx != std::size_t(-1)) 217   28 if (arg_idx != std::size_t(-1))
218   { 218   {
219   // identifier 219   // identifier
HITCBC 220   18 warg = args.get(arg_idx); 220   18 warg = args.get(arg_idx);
221   } 221   }
222   else 222   else
223   { 223   {
224   // unsigned integer 224   // unsigned integer
HITCBC 225   10 warg = args.get(arg_name); 225   10 warg = args.get(arg_name);
226   } 226   }
227   227  
228   // get unsigned int value from that format arg 228   // get unsigned int value from that format arg
HITCBC 229   28 w = warg.value(); 229   28 w = warg.value();
HITCBC 230   28 } 230   28 }
231   231  
232   char const* 232   char const*
HITCBC 233   115 integer_formatter_impl:: 233   115 integer_formatter_impl::
234   parse(format_parse_context& ctx) 234   parse(format_parse_context& ctx)
235   { 235   {
HITCBC 236   115 char const* it = ctx.begin(); 236   115 char const* it = ctx.begin();
HITCBC 237   115 char const* end = ctx.end(); 237   115 char const* end = ctx.end();
HITCBC 238   115 BOOST_ASSERT(it != end); 238   115 BOOST_ASSERT(it != end);
239   239  
240   // fill / align 240   // fill / align
HITCBC 241   115 if (end - it > 2) 241   115 if (end - it > 2)
242   { 242   {
HITCBC 243   57 if (*it != '{' && 243   57 if (*it != '{' &&
HITCBC 244   57 *it != '}' && 244   57 *it != '}' &&
HITCBC 245   53 (*(it + 1) == '<' || 245   53 (*(it + 1) == '<' ||
HITCBC 246   49 *(it + 1) == '>' || 246   49 *(it + 1) == '>' ||
HITCBC 247   27 *(it + 1) == '^')) 247   27 *(it + 1) == '^'))
248   { 248   {
HITCBC 249   30 fill = *it; 249   30 fill = *it;
HITCBC 250   30 align = *(it + 1); 250   30 align = *(it + 1);
HITCBC 251   30 it += 2; 251   30 it += 2;
252   } 252   }
253   } 253   }
254   254  
255   // align 255   // align
HITCBC 256   115 if (align == '\0' && 256   115 if (align == '\0' &&
HITCBC 257   85 (*it == '<' || 257   85 (*it == '<' ||
HITCBC 258   85 *it == '>' || 258   85 *it == '>' ||
HITCBC 259   77 *it == '^')) 259   77 *it == '^'))
260   { 260   {
HITCBC 261   12 align = *it++; 261   12 align = *it++;
262   } 262   }
263   263  
264   // sign 264   // sign
HITCBC 265   115 if (*it == '+' || 265   115 if (*it == '+' ||
HITCBC 266   109 *it == '-' || 266   109 *it == '-' ||
HITCBC 267   109 *it == ' ') 267   109 *it == ' ')
268   { 268   {
HITCBC 269   12 sign = *it++; 269   12 sign = *it++;
270   } 270   }
271   271  
272   // # 272   // #
HITCBC 273   115 if (*it == '#') 273   115 if (*it == '#')
274   { 274   {
275   // alternate form not supported 275   // alternate form not supported
HITCBC 276   2 ++it; 276   2 ++it;
277   } 277   }
278   278  
279   // 0 279   // 0
HITCBC 280   115 if (*it == '0') 280   115 if (*it == '0')
281   { 281   {
HITCBC 282   8 zeros = *it++; 282   8 zeros = *it++;
283   } 283   }
284   284  
285   // width 285   // width
HITCBC 286   115 char const* it0 = it; 286   115 char const* it0 = it;
HITCBC 287   115 constexpr auto width_rule = grammar::variant_rule( 287   115 constexpr auto width_rule = grammar::variant_rule(
288   grammar::unsigned_rule<std::size_t>{}, 288   grammar::unsigned_rule<std::size_t>{},
289   grammar::tuple_rule( 289   grammar::tuple_rule(
290   grammar::squelch( 290   grammar::squelch(
291   grammar::delim_rule('{')), 291   grammar::delim_rule('{')),
292   grammar::optional_rule( 292   grammar::optional_rule(
293   arg_id_rule), 293   arg_id_rule),
294   grammar::squelch( 294   grammar::squelch(
295   grammar::delim_rule('}')))); 295   grammar::delim_rule('}'))));
HITCBC 296   115 auto rw = grammar::parse(it, end, width_rule); 296   115 auto rw = grammar::parse(it, end, width_rule);
HITCBC 297   115 if (!rw) 297   115 if (!rw)
298   { 298   {
299   // rewind 299   // rewind
HITCBC 300   73 it = it0; 300   73 it = it0;
301   } 301   }
HITCBC 302   42 else if (align != '\0') 302   42 else if (align != '\0')
303   { 303   {
304   // width is ignored when align is '\0' 304   // width is ignored when align is '\0'
HITCBC 305   42 if (rw->index() == 0) 305   42 if (rw->index() == 0)
306   { 306   {
307   // unsigned_rule 307   // unsigned_rule
HITCBC 308   24 width = variant2::get<0>(*rw); 308   24 width = variant2::get<0>(*rw);
309   } 309   }
310   else 310   else
311   { 311   {
312   // arg_id: store the id idx or string 312   // arg_id: store the id idx or string
HITCBC 313   18 auto& arg_id = variant2::get<1>(*rw); 313   18 auto& arg_id = variant2::get<1>(*rw);
HITCBC 314   18 if (!arg_id) 314   18 if (!arg_id)
315   { 315   {
316   // empty arg_id, use and consume 316   // empty arg_id, use and consume
317   // the next arg idx 317   // the next arg idx
HITCBC 318   4 width_idx = ctx.next_arg_id(); 318   4 width_idx = ctx.next_arg_id();
319   } 319   }
HITCBC 320   14 else if (arg_id->index() == 0) 320   14 else if (arg_id->index() == 0)
321   { 321   {
322   // string identifier 322   // string identifier
HITCBC 323   6 width_name = variant2::get<0>(*arg_id); 323   6 width_name = variant2::get<0>(*arg_id);
324   } 324   }
325   else 325   else
326   { 326   {
327   // integer identifier: use the 327   // integer identifier: use the
328   // idx of this format_arg 328   // idx of this format_arg
HITCBC 329   8 width_idx = variant2::get<1>(*arg_id); 329   8 width_idx = variant2::get<1>(*arg_id);
330   } 330   }
331   } 331   }
332   } 332   }
333   333  
334   // type is parsed but doesn't have to 334   // type is parsed but doesn't have to
335   // be stored for strings 335   // be stored for strings
HITCBC 336   115 if (*it == 'd') 336   115 if (*it == 'd')
337   { 337   {
338   // we don't include other presentation 338   // we don't include other presentation
339   // modes for integers as they are not 339   // modes for integers as they are not
340   // recommended or generally used in 340   // recommended or generally used in
341   // urls 341   // urls
HITCBC 342   55 ++it; 342   55 ++it;
343   } 343   }
344   344  
345   // we should have arrived at the end now 345   // we should have arrived at the end now
HITCBC 346   115 if (*it != '}') 346   115 if (*it != '}')
347   { 347   {
HITCBC 348   1 urls::detail::throw_invalid_argument(); 348   1 urls::detail::throw_invalid_argument();
349   } 349   }
350   350  
HITCBC 351   114 return it; 351   114 return it;
352   } 352   }
353   353  
354   std::size_t 354   std::size_t
HITCBC 355   43 integer_formatter_impl:: 355   43 integer_formatter_impl::
356   measure( 356   measure(
357   long long int v, 357   long long int v,
358   measure_context& ctx, 358   measure_context& ctx,
359   grammar::lut_chars const& cs) const 359   grammar::lut_chars const& cs) const
360   { 360   {
HITCBC 361   43 std::size_t dn = 0; 361   43 std::size_t dn = 0;
HITCBC 362   43 std::size_t n = 0; 362   43 std::size_t n = 0;
HITCBC 363   43 if (v < 0) 363   43 if (v < 0)
364   { 364   {
HITCBC 365   2 dn += measure_one('-', cs); 365   2 dn += measure_one('-', cs);
HITCBC 366   2 ++n; 366   2 ++n;
367   } 367   }
HITCBC 368   41 else if (sign != '-') 368   41 else if (sign != '-')
369   { 369   {
HITCBC 370   4 dn += measure_one(sign, cs); 370   4 dn += measure_one(sign, cs);
HITCBC 371   4 ++n; 371   4 ++n;
372   } 372   }
373   // Use unsigned to avoid UB when v == LLONG_MIN 373   // Use unsigned to avoid UB when v == LLONG_MIN
HITCBC 374   43 unsigned long long int uv = v < 0 374   43 unsigned long long int uv = v < 0
HITCBC 375   43 ? 0ull - static_cast<unsigned long long int>(v) 375   43 ? 0ull - static_cast<unsigned long long int>(v)
376   : static_cast<unsigned long long int>(v); 376   : static_cast<unsigned long long int>(v);
377   do 377   do
378   { 378   {
HITCBC 379   102 int d = static_cast<int>(uv % 10); 379   102 int d = static_cast<int>(uv % 10);
HITCBC 380   102 uv /= 10; 380   102 uv /= 10;
HITCBC 381   102 dn += measure_one('0' + static_cast<char>(d), cs); 381   102 dn += measure_one('0' + static_cast<char>(d), cs);
HITCBC 382   102 ++n; 382   102 ++n;
383   } 383   }
HITCBC 384   102 while (uv > 0); 384   102 while (uv > 0);
385   385  
HITCBC 386   43 std::size_t w = width; 386   43 std::size_t w = width;
HITCBC 387   83 if (width_idx != std::size_t(-1) || 387   83 if (width_idx != std::size_t(-1) ||
HITCBC 388   40 !width_name.empty()) 388   40 !width_name.empty())
389   { 389   {
HITCBC 390   5 get_width_from_args( 390   5 get_width_from_args(
HITCBC 391   5 width_idx, width_name, ctx.args(), w); 391   5 width_idx, width_name, ctx.args(), w);
392   } 392   }
HITCBC 393   43 if (w > n) 393   43 if (w > n)
394   { 394   {
HITCBC 395   12 if (!zeros) 395   12 if (!zeros)
HITCBC 396   9 dn += measure_one(fill, cs) * (w - n); 396   9 dn += measure_one(fill, cs) * (w - n);
397   else 397   else
HITCBC 398   3 dn += measure_one('0', cs) * (w - n); 398   3 dn += measure_one('0', cs) * (w - n);
399   } 399   }
HITCBC 400   86 return ctx.out() + dn; 400   86 return ctx.out() + dn;
401   } 401   }
402   402  
403   std::size_t 403   std::size_t
HITCBC 404   14 integer_formatter_impl:: 404   14 integer_formatter_impl::
405   measure( 405   measure(
406   unsigned long long int v, 406   unsigned long long int v,
407   measure_context& ctx, 407   measure_context& ctx,
408   grammar::lut_chars const& cs) const 408   grammar::lut_chars const& cs) const
409   { 409   {
HITCBC 410   14 std::size_t dn = 0; 410   14 std::size_t dn = 0;
HITCBC 411   14 std::size_t n = 0; 411   14 std::size_t n = 0;
HITCBC 412   14 if (sign != '-') 412   14 if (sign != '-')
413   { 413   {
HITCBC 414   2 dn += measure_one(sign, cs); 414   2 dn += measure_one(sign, cs);
HITCBC 415   2 ++n; 415   2 ++n;
416   } 416   }
417   do 417   do
418   { 418   {
HITCBC 419   53 int d = v % 10; 419   53 int d = v % 10;
HITCBC 420   53 v /= 10; 420   53 v /= 10;
HITCBC 421   53 dn += measure_one('0' + static_cast<char>(d), cs); 421   53 dn += measure_one('0' + static_cast<char>(d), cs);
HITCBC 422   53 ++n; 422   53 ++n;
423   } 423   }
HITCBC 424   53 while (v != 0); 424   53 while (v != 0);
425   425  
HITCBC 426   14 std::size_t w = width; 426   14 std::size_t w = width;
HITCBC 427   25 if (width_idx != std::size_t(-1) || 427   25 if (width_idx != std::size_t(-1) ||
HITCBC 428   11 !width_name.empty()) 428   11 !width_name.empty())
429   { 429   {
HITCBC 430   4 get_width_from_args( 430   4 get_width_from_args(
HITCBC 431   4 width_idx, width_name, ctx.args(), w); 431   4 width_idx, width_name, ctx.args(), w);
432   } 432   }
HITCBC 433   14 if (w > n) 433   14 if (w > n)
434   { 434   {
HITCBC 435   8 if (!zeros) 435   8 if (!zeros)
HITCBC 436   7 dn += measure_one(fill, cs) * (w - n); 436   7 dn += measure_one(fill, cs) * (w - n);
437   else 437   else
HITCBC 438   1 dn += measure_one('0', cs) * (w - n); 438   1 dn += measure_one('0', cs) * (w - n);
439   } 439   }
HITCBC 440   28 return ctx.out() + dn; 440   28 return ctx.out() + dn;
441   } 441   }
442   442  
443   char* 443   char*
HITCBC 444   43 integer_formatter_impl:: 444   43 integer_formatter_impl::
445   format( 445   format(
446   long long int v, 446   long long int v,
447   format_context& ctx, 447   format_context& ctx,
448   grammar::lut_chars const& cs) const 448   grammar::lut_chars const& cs) const
449   { 449   {
450   // get n digits 450   // get n digits
451   // Use unsigned to avoid UB when v == LLONG_MIN 451   // Use unsigned to avoid UB when v == LLONG_MIN
HITCBC 452   43 bool const neg = v < 0; 452   43 bool const neg = v < 0;
HITCBC 453   43 unsigned long long int uv = neg 453   43 unsigned long long int uv = neg
HITCBC 454   43 ? 0ull - static_cast<unsigned long long int>(v) 454   43 ? 0ull - static_cast<unsigned long long int>(v)
455   : static_cast<unsigned long long int>(v); 455   : static_cast<unsigned long long int>(v);
HITCBC 456   43 unsigned long long int uv0 = uv; 456   43 unsigned long long int uv0 = uv;
HITCBC 457   43 unsigned long long int p = 1; 457   43 unsigned long long int p = 1;
HITCBC 458   43 std::size_t n = 0; 458   43 std::size_t n = 0;
HITCBC 459   43 if (neg || sign != '-') 459   43 if (neg || sign != '-')
460   { 460   {
HITCBC 461   6 ++n; 461   6 ++n;
462   } 462   }
463   do 463   do
464   { 464   {
HITCBC 465   102 if (uv >= 10) 465   102 if (uv >= 10)
HITCBC 466   59 p *= 10; 466   59 p *= 10;
HITCBC 467   102 uv /= 10; 467   102 uv /= 10;
HITCBC 468   102 ++n; 468   102 ++n;
469   } 469   }
HITCBC 470   102 while (uv > 0); 470   102 while (uv > 0);
471   static constexpr auto m = 471   static constexpr auto m =
472   std::numeric_limits<long long int>::digits10; 472   std::numeric_limits<long long int>::digits10;
HITCBC 473   43 BOOST_ASSERT(n <= m + 2); 473   43 BOOST_ASSERT(n <= m + 2);
474   ignore_unused(m); 474   ignore_unused(m);
475   475  
476   // get pad 476   // get pad
HITCBC 477   43 std::size_t w = width; 477   43 std::size_t w = width;
HITCBC 478   83 if (width_idx != std::size_t(-1) || 478   83 if (width_idx != std::size_t(-1) ||
HITCBC 479   40 !width_name.empty()) 479   40 !width_name.empty())
480   { 480   {
HITCBC 481   5 get_width_from_args( 481   5 get_width_from_args(
HITCBC 482   5 width_idx, width_name, ctx.args(), w); 482   5 width_idx, width_name, ctx.args(), w);
483   } 483   }
HITCBC 484   43 std::size_t lpad = 0; 484   43 std::size_t lpad = 0;
HITCBC 485   43 std::size_t rpad = 0; 485   43 std::size_t rpad = 0;
HITCBC 486   43 if (w > n) 486   43 if (w > n)
487   { 487   {
HITCBC 488   12 std::size_t pad = w - n; 488   12 std::size_t pad = w - n;
HITCBC 489   12 if (zeros) 489   12 if (zeros)
490   { 490   {
HITCBC 491   3 lpad = pad; 491   3 lpad = pad;
492   } 492   }
493   else 493   else
494   { 494   {
HITCBC 495   9 switch (align) 495   9 switch (align)
496   { 496   {
HITCBC 497   1 case '<': 497   1 case '<':
HITCBC 498   1 rpad = pad; 498   1 rpad = pad;
HITCBC 499   1 break; 499   1 break;
HITCBC 500   6 case '>': 500   6 case '>':
HITCBC 501   6 lpad = pad; 501   6 lpad = pad;
HITCBC 502   6 break; 502   6 break;
HITCBC 503   2 case '^': 503   2 case '^':
HITCBC 504   2 lpad = pad / 2; 504   2 lpad = pad / 2;
HITCBC 505   2 rpad = pad - lpad; 505   2 rpad = pad - lpad;
HITCBC 506   2 break; 506   2 break;
507   } 507   }
508   } 508   }
509   } 509   }
510   510  
511   // write 511   // write
HITCBC 512   43 uv = uv0; 512   43 uv = uv0;
HITCBC 513   43 char* out = ctx.out(); 513   43 char* out = ctx.out();
HITCBC 514   43 if (!zeros) 514   43 if (!zeros)
515   { 515   {
HITCBC 516   68 for (std::size_t i = 0; i < lpad; ++i) 516   68 for (std::size_t i = 0; i < lpad; ++i)
HITCBC 517   28 encode_one(out, fill, cs); 517   28 encode_one(out, fill, cs);
518   } 518   }
HITCBC 519   43 if (neg) 519   43 if (neg)
520   { 520   {
HITCBC 521   2 encode_one(out, '-', cs); 521   2 encode_one(out, '-', cs);
HITCBC 522   2 --n; 522   2 --n;
523   } 523   }
HITCBC 524   41 else if (sign != '-') 524   41 else if (sign != '-')
525   { 525   {
HITCBC 526   4 encode_one(out, sign, cs); 526   4 encode_one(out, sign, cs);
HITCBC 527   4 --n; 527   4 --n;
528   } 528   }
HITCBC 529   43 if (zeros) 529   43 if (zeros)
530   { 530   {
HITCBC 531   13 for (std::size_t i = 0; i < lpad; ++i) 531   13 for (std::size_t i = 0; i < lpad; ++i)
HITCBC 532   10 encode_one(out, '0', cs); 532   10 encode_one(out, '0', cs);
533   } 533   }
HITCBC 534   145 while (n) 534   145 while (n)
535   { 535   {
HITCBC 536   102 unsigned long long int d = uv / p; 536   102 unsigned long long int d = uv / p;
HITCBC 537   102 encode_one(out, '0' + static_cast<char>(d), cs); 537   102 encode_one(out, '0' + static_cast<char>(d), cs);
HITCBC 538   102 --n; 538   102 --n;
HITCBC 539   102 uv %= p; 539   102 uv %= p;
HITCBC 540   102 p /= 10; 540   102 p /= 10;
541   } 541   }
HITCBC 542   43 if (!zeros) 542   43 if (!zeros)
543   { 543   {
HITCBC 544   48 for (std::size_t i = 0; i < rpad; ++i) 544   48 for (std::size_t i = 0; i < rpad; ++i)
HITCBC 545   8 encode_one(out, fill, cs); 545   8 encode_one(out, fill, cs);
546   } 546   }
HITCBC 547   43 return out; 547   43 return out;
548   } 548   }
549   549  
550   char* 550   char*
HITCBC 551   14 integer_formatter_impl:: 551   14 integer_formatter_impl::
552   format( 552   format(
553   unsigned long long int v, 553   unsigned long long int v,
554   format_context& ctx, 554   format_context& ctx,
555   grammar::lut_chars const& cs) const 555   grammar::lut_chars const& cs) const
556   { 556   {
557   // get n digits 557   // get n digits
HITCBC 558   14 unsigned long long int v0 = v; 558   14 unsigned long long int v0 = v;
HITCBC 559   14 unsigned long long int p = 1; 559   14 unsigned long long int p = 1;
HITCBC 560   14 std::size_t n = 0; 560   14 std::size_t n = 0;
HITCBC 561   14 if (sign != '-') 561   14 if (sign != '-')
562   { 562   {
HITCBC 563   2 ++n; 563   2 ++n;
564   } 564   }
565   do 565   do
566   { 566   {
HITCBC 567   53 if (v >= 10) 567   53 if (v >= 10)
HITCBC 568   39 p *= 10; 568   39 p *= 10;
HITCBC 569   53 v /= 10; 569   53 v /= 10;
HITCBC 570   53 ++n; 570   53 ++n;
571   } 571   }
HITCBC 572   53 while (v > 0); 572   53 while (v > 0);
573   static constexpr auto m = 573   static constexpr auto m =
574   std::numeric_limits<unsigned long long int>::digits10; 574   std::numeric_limits<unsigned long long int>::digits10;
HITCBC 575   14 BOOST_ASSERT(n <= m + 2); 575   14 BOOST_ASSERT(n <= m + 2);
576   ignore_unused(m); 576   ignore_unused(m);
577   577  
578   // get pad 578   // get pad
HITCBC 579   14 std::size_t w = width; 579   14 std::size_t w = width;
HITCBC 580   25 if (width_idx != std::size_t(-1) || 580   25 if (width_idx != std::size_t(-1) ||
HITCBC 581   11 !width_name.empty()) 581   11 !width_name.empty())
582   { 582   {
HITCBC 583   4 get_width_from_args( 583   4 get_width_from_args(
HITCBC 584   4 width_idx, width_name, ctx.args(), w); 584   4 width_idx, width_name, ctx.args(), w);
585   } 585   }
HITCBC 586   14 std::size_t lpad = 0; 586   14 std::size_t lpad = 0;
HITCBC 587   14 std::size_t rpad = 0; 587   14 std::size_t rpad = 0;
HITCBC 588   14 if (w > n) 588   14 if (w > n)
589   { 589   {
HITCBC 590   8 std::size_t pad = w - n; 590   8 std::size_t pad = w - n;
HITCBC 591   8 if (zeros) 591   8 if (zeros)
592   { 592   {
HITCBC 593   1 lpad = pad; 593   1 lpad = pad;
594   } 594   }
595   else 595   else
596   { 596   {
HITCBC 597   7 switch (align) 597   7 switch (align)
598   { 598   {
HITCBC 599   1 case '<': 599   1 case '<':
HITCBC 600   1 rpad = pad; 600   1 rpad = pad;
HITCBC 601   1 break; 601   1 break;
HITCBC 602   5 case '>': 602   5 case '>':
HITCBC 603   5 lpad = pad; 603   5 lpad = pad;
HITCBC 604   5 break; 604   5 break;
HITCBC 605   1 case '^': 605   1 case '^':
HITCBC 606   1 lpad = pad / 2; 606   1 lpad = pad / 2;
HITCBC 607   1 rpad = pad - lpad; 607   1 rpad = pad - lpad;
HITCBC 608   1 break; 608   1 break;
609   } 609   }
610   } 610   }
611   } 611   }
612   612  
613   // write 613   // write
HITCBC 614   14 v = v0; 614   14 v = v0;
HITCBC 615   14 char* out = ctx.out(); 615   14 char* out = ctx.out();
HITCBC 616   14 if (!zeros) 616   14 if (!zeros)
617   { 617   {
HITCBC 618   35 for (std::size_t i = 0; i < lpad; ++i) 618   35 for (std::size_t i = 0; i < lpad; ++i)
HITCBC 619   22 encode_one(out, fill, cs); 619   22 encode_one(out, fill, cs);
620   } 620   }
HITCBC 621   14 if (sign != '-') 621   14 if (sign != '-')
622   { 622   {
HITCBC 623   2 encode_one(out, sign, cs); 623   2 encode_one(out, sign, cs);
HITCBC 624   2 --n; 624   2 --n;
625   } 625   }
HITCBC 626   14 if (zeros) 626   14 if (zeros)
627   { 627   {
HITCBC 628   5 for (std::size_t i = 0; i < lpad; ++i) 628   5 for (std::size_t i = 0; i < lpad; ++i)
HITCBC 629   4 encode_one(out, '0', cs); 629   4 encode_one(out, '0', cs);
630   } 630   }
HITCBC 631   67 while (n) 631   67 while (n)
632   { 632   {
HITCBC 633   53 unsigned long long int d = v / p; 633   53 unsigned long long int d = v / p;
HITCBC 634   53 encode_one(out, '0' + static_cast<char>(d), cs); 634   53 encode_one(out, '0' + static_cast<char>(d), cs);
HITCBC 635   53 --n; 635   53 --n;
HITCBC 636   53 v %= p; 636   53 v %= p;
HITCBC 637   53 p /= 10; 637   53 p /= 10;
638   } 638   }
HITCBC 639   14 if (!zeros) 639   14 if (!zeros)
640   { 640   {
HITCBC 641   19 for (std::size_t i = 0; i < rpad; ++i) 641   19 for (std::size_t i = 0; i < rpad; ++i)
HITCBC 642   6 encode_one(out, fill, cs); 642   6 encode_one(out, fill, cs);
643   } 643   }
HITCBC 644   14 return out; 644   14 return out;
645   } 645   }
646   646  
647   } // detail 647   } // detail
648   } // urls 648   } // urls
649   } // boost 649   } // boost
650   650