• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // POSIX spec:
3 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
4 //
5 #include "absl/strings/internal/str_format/arg.h"
6 
7 #include <cassert>
8 #include <cerrno>
9 #include <cstdlib>
10 #include <string>
11 #include <type_traits>
12 
13 #include "absl/base/port.h"
14 #include "absl/strings/internal/str_format/float_conversion.h"
15 #include "absl/strings/numbers.h"
16 
17 namespace absl {
18 ABSL_NAMESPACE_BEGIN
19 namespace str_format_internal {
20 namespace {
21 
22 // Reduce *capacity by s.size(), clipped to a 0 minimum.
ReducePadding(string_view s,size_t * capacity)23 void ReducePadding(string_view s, size_t *capacity) {
24   *capacity = Excess(s.size(), *capacity);
25 }
26 
27 // Reduce *capacity by n, clipped to a 0 minimum.
ReducePadding(size_t n,size_t * capacity)28 void ReducePadding(size_t n, size_t *capacity) {
29   *capacity = Excess(n, *capacity);
30 }
31 
32 template <typename T>
33 struct MakeUnsigned : std::make_unsigned<T> {};
34 template <>
35 struct MakeUnsigned<absl::int128> {
36   using type = absl::uint128;
37 };
38 template <>
39 struct MakeUnsigned<absl::uint128> {
40   using type = absl::uint128;
41 };
42 
43 template <typename T>
44 struct IsSigned : std::is_signed<T> {};
45 template <>
46 struct IsSigned<absl::int128> : std::true_type {};
47 template <>
48 struct IsSigned<absl::uint128> : std::false_type {};
49 
50 // Integral digit printer.
51 // Call one of the PrintAs* routines after construction once.
52 // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
53 class IntDigits {
54  public:
55   // Print the unsigned integer as octal.
56   // Supports unsigned integral types and uint128.
57   template <typename T>
PrintAsOct(T v)58   void PrintAsOct(T v) {
59     static_assert(!IsSigned<T>::value, "");
60     char *p = storage_ + sizeof(storage_);
61     do {
62       *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
63       v >>= 3;
64     } while (v);
65     start_ = p;
66     size_ = storage_ + sizeof(storage_) - p;
67   }
68 
69   // Print the signed or unsigned integer as decimal.
70   // Supports all integral types.
71   template <typename T>
PrintAsDec(T v)72   void PrintAsDec(T v) {
73     static_assert(std::is_integral<T>::value, "");
74     start_ = storage_;
75     size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
76   }
77 
PrintAsDec(int128 v)78   void PrintAsDec(int128 v) {
79     auto u = static_cast<uint128>(v);
80     bool add_neg = false;
81     if (v < 0) {
82       add_neg = true;
83       u = uint128{} - u;
84     }
85     PrintAsDec(u, add_neg);
86   }
87 
PrintAsDec(uint128 v,bool add_neg=false)88   void PrintAsDec(uint128 v, bool add_neg = false) {
89     // This function can be sped up if needed. We can call FastIntToBuffer
90     // twice, or fix FastIntToBuffer to support uint128.
91     char *p = storage_ + sizeof(storage_);
92     do {
93       p -= 2;
94       numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
95       v /= 100;
96     } while (v);
97     if (p[0] == '0') {
98       // We printed one too many hexits.
99       ++p;
100     }
101     if (add_neg) {
102       *--p = '-';
103     }
104     size_ = storage_ + sizeof(storage_) - p;
105     start_ = p;
106   }
107 
108   // Print the unsigned integer as hex using lowercase.
109   // Supports unsigned integral types and uint128.
110   template <typename T>
PrintAsHexLower(T v)111   void PrintAsHexLower(T v) {
112     static_assert(!IsSigned<T>::value, "");
113     char *p = storage_ + sizeof(storage_);
114 
115     do {
116       p -= 2;
117       constexpr const char* table = numbers_internal::kHexTable;
118       std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
119       if (sizeof(T) == 1) break;
120       v >>= 8;
121     } while (v);
122     if (p[0] == '0') {
123       // We printed one too many digits.
124       ++p;
125     }
126     start_ = p;
127     size_ = storage_ + sizeof(storage_) - p;
128   }
129 
130   // Print the unsigned integer as hex using uppercase.
131   // Supports unsigned integral types and uint128.
132   template <typename T>
PrintAsHexUpper(T v)133   void PrintAsHexUpper(T v) {
134     static_assert(!IsSigned<T>::value, "");
135     char *p = storage_ + sizeof(storage_);
136 
137     // kHexTable is only lowercase, so do it manually for uppercase.
138     do {
139       *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
140       v >>= 4;
141     } while (v);
142     start_ = p;
143     size_ = storage_ + sizeof(storage_) - p;
144   }
145 
146   // The printed value including the '-' sign if available.
147   // For inputs of value `0`, this will return "0"
with_neg_and_zero() const148   string_view with_neg_and_zero() const { return {start_, size_}; }
149 
150   // The printed value not including the '-' sign.
151   // For inputs of value `0`, this will return "".
without_neg_or_zero() const152   string_view without_neg_or_zero() const {
153     static_assert('-' < '0', "The check below verifies both.");
154     size_t advance = start_[0] <= '0' ? 1 : 0;
155     return {start_ + advance, size_ - advance};
156   }
157 
is_negative() const158   bool is_negative() const { return start_[0] == '-'; }
159 
160  private:
161   const char *start_;
162   size_t size_;
163   // Max size: 128 bit value as octal -> 43 digits, plus sign char
164   char storage_[128 / 3 + 1 + 1];
165 };
166 
167 // Note: 'o' conversions do not have a base indicator, it's just that
168 // the '#' flag is specified to modify the precision for 'o' conversions.
BaseIndicator(const IntDigits & as_digits,const FormatConversionSpecImpl conv)169 string_view BaseIndicator(const IntDigits &as_digits,
170                           const FormatConversionSpecImpl conv) {
171   // always show 0x for %p.
172   bool alt = conv.has_alt_flag() ||
173              conv.conversion_char() == FormatConversionCharInternal::p;
174   bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
175               conv.conversion_char() == FormatConversionCharInternal::X ||
176               conv.conversion_char() == FormatConversionCharInternal::p);
177   // From the POSIX description of '#' flag:
178   //   "For x or X conversion specifiers, a non-zero result shall have
179   //   0x (or 0X) prefixed to it."
180   if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
181     return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
182                                                                      : "0x";
183   }
184   return {};
185 }
186 
SignColumn(bool neg,const FormatConversionSpecImpl conv)187 string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
188   if (conv.conversion_char() == FormatConversionCharInternal::d ||
189       conv.conversion_char() == FormatConversionCharInternal::i) {
190     if (neg) return "-";
191     if (conv.has_show_pos_flag()) return "+";
192     if (conv.has_sign_col_flag()) return " ";
193   }
194   return {};
195 }
196 
ConvertCharImpl(unsigned char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)197 bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
198                      FormatSinkImpl *sink) {
199   size_t fill = 0;
200   if (conv.width() >= 0) fill = conv.width();
201   ReducePadding(1, &fill);
202   if (!conv.has_left_flag()) sink->Append(fill, ' ');
203   sink->Append(1, v);
204   if (conv.has_left_flag()) sink->Append(fill, ' ');
205   return true;
206 }
207 
ConvertIntImplInnerSlow(const IntDigits & as_digits,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)208 bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
209                              const FormatConversionSpecImpl conv,
210                              FormatSinkImpl *sink) {
211   // Print as a sequence of Substrings:
212   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
213   size_t fill = 0;
214   if (conv.width() >= 0) fill = conv.width();
215 
216   string_view formatted = as_digits.without_neg_or_zero();
217   ReducePadding(formatted, &fill);
218 
219   string_view sign = SignColumn(as_digits.is_negative(), conv);
220   ReducePadding(sign, &fill);
221 
222   string_view base_indicator = BaseIndicator(as_digits, conv);
223   ReducePadding(base_indicator, &fill);
224 
225   int precision = conv.precision();
226   bool precision_specified = precision >= 0;
227   if (!precision_specified)
228     precision = 1;
229 
230   if (conv.has_alt_flag() &&
231       conv.conversion_char() == FormatConversionCharInternal::o) {
232     // From POSIX description of the '#' (alt) flag:
233     //   "For o conversion, it increases the precision (if necessary) to
234     //   force the first digit of the result to be zero."
235     if (formatted.empty() || *formatted.begin() != '0') {
236       int needed = static_cast<int>(formatted.size()) + 1;
237       precision = std::max(precision, needed);
238     }
239   }
240 
241   size_t num_zeroes = Excess(formatted.size(), precision);
242   ReducePadding(num_zeroes, &fill);
243 
244   size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
245   size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
246 
247   // From POSIX description of the '0' (zero) flag:
248   //   "For d, i, o, u, x, and X conversion specifiers, if a precision
249   //   is specified, the '0' flag is ignored."
250   if (!precision_specified && conv.has_zero_flag()) {
251     num_zeroes += num_left_spaces;
252     num_left_spaces = 0;
253   }
254 
255   sink->Append(num_left_spaces, ' ');
256   sink->Append(sign);
257   sink->Append(base_indicator);
258   sink->Append(num_zeroes, '0');
259   sink->Append(formatted);
260   sink->Append(num_right_spaces, ' ');
261   return true;
262 }
263 
264 template <typename T>
ConvertIntArg(T v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)265 bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
266                    FormatSinkImpl *sink) {
267   using U = typename MakeUnsigned<T>::type;
268   IntDigits as_digits;
269 
270   // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
271   // it to complain about a switch/case type mismatch, even though both are
272   // FormatConverionChar.  Likely this is because at this point
273   // FormatConversionChar is declared, but not defined.
274   switch (static_cast<uint8_t>(conv.conversion_char())) {
275     case static_cast<uint8_t>(FormatConversionCharInternal::c):
276       return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
277 
278     case static_cast<uint8_t>(FormatConversionCharInternal::o):
279       as_digits.PrintAsOct(static_cast<U>(v));
280       break;
281 
282     case static_cast<uint8_t>(FormatConversionCharInternal::x):
283       as_digits.PrintAsHexLower(static_cast<U>(v));
284       break;
285     case static_cast<uint8_t>(FormatConversionCharInternal::X):
286       as_digits.PrintAsHexUpper(static_cast<U>(v));
287       break;
288 
289     case static_cast<uint8_t>(FormatConversionCharInternal::u):
290       as_digits.PrintAsDec(static_cast<U>(v));
291       break;
292 
293     case static_cast<uint8_t>(FormatConversionCharInternal::d):
294     case static_cast<uint8_t>(FormatConversionCharInternal::i):
295       as_digits.PrintAsDec(v);
296       break;
297 
298     case static_cast<uint8_t>(FormatConversionCharInternal::a):
299     case static_cast<uint8_t>(FormatConversionCharInternal::e):
300     case static_cast<uint8_t>(FormatConversionCharInternal::f):
301     case static_cast<uint8_t>(FormatConversionCharInternal::g):
302     case static_cast<uint8_t>(FormatConversionCharInternal::A):
303     case static_cast<uint8_t>(FormatConversionCharInternal::E):
304     case static_cast<uint8_t>(FormatConversionCharInternal::F):
305     case static_cast<uint8_t>(FormatConversionCharInternal::G):
306       return ConvertFloatImpl(static_cast<double>(v), conv, sink);
307 
308     default:
309        ABSL_INTERNAL_ASSUME(false);
310   }
311 
312   if (conv.is_basic()) {
313     sink->Append(as_digits.with_neg_and_zero());
314     return true;
315   }
316   return ConvertIntImplInnerSlow(as_digits, conv, sink);
317 }
318 
319 template <typename T>
ConvertFloatArg(T v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)320 bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
321                      FormatSinkImpl *sink) {
322   return FormatConversionCharIsFloat(conv.conversion_char()) &&
323          ConvertFloatImpl(v, conv, sink);
324 }
325 
ConvertStringArg(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)326 inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
327                              FormatSinkImpl *sink) {
328   if (conv.is_basic()) {
329     sink->Append(v);
330     return true;
331   }
332   return sink->PutPaddedString(v, conv.width(), conv.precision(),
333                                conv.has_left_flag());
334 }
335 
336 }  // namespace
337 
338 // ==================== Strings ====================
FormatConvertImpl(const std::string & v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)339 StringConvertResult FormatConvertImpl(const std::string &v,
340                                       const FormatConversionSpecImpl conv,
341                                       FormatSinkImpl *sink) {
342   return {ConvertStringArg(v, conv, sink)};
343 }
344 
FormatConvertImpl(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)345 StringConvertResult FormatConvertImpl(string_view v,
346                                       const FormatConversionSpecImpl conv,
347                                       FormatSinkImpl *sink) {
348   return {ConvertStringArg(v, conv, sink)};
349 }
350 
351 ArgConvertResult<FormatConversionCharSetUnion(
352     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
FormatConvertImpl(const char * v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)353 FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
354                   FormatSinkImpl *sink) {
355   if (conv.conversion_char() == FormatConversionCharInternal::p)
356     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
357   size_t len;
358   if (v == nullptr) {
359     len = 0;
360   } else if (conv.precision() < 0) {
361     len = std::strlen(v);
362   } else {
363     // If precision is set, we look for the NUL-terminator on the valid range.
364     len = std::find(v, v + conv.precision(), '\0') - v;
365   }
366   return {ConvertStringArg(string_view(v, len), conv, sink)};
367 }
368 
369 // ==================== Raw pointers ====================
FormatConvertImpl(VoidPtr v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)370 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
371     VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
372   if (!v.value) {
373     sink->Append("(nil)");
374     return {true};
375   }
376   IntDigits as_digits;
377   as_digits.PrintAsHexLower(v.value);
378   return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
379 }
380 
381 // ==================== Floats ====================
FormatConvertImpl(float v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)382 FloatingConvertResult FormatConvertImpl(float v,
383                                         const FormatConversionSpecImpl conv,
384                                         FormatSinkImpl *sink) {
385   return {ConvertFloatArg(v, conv, sink)};
386 }
FormatConvertImpl(double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)387 FloatingConvertResult FormatConvertImpl(double v,
388                                         const FormatConversionSpecImpl conv,
389                                         FormatSinkImpl *sink) {
390   return {ConvertFloatArg(v, conv, sink)};
391 }
FormatConvertImpl(long double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)392 FloatingConvertResult FormatConvertImpl(long double v,
393                                         const FormatConversionSpecImpl conv,
394                                         FormatSinkImpl *sink) {
395   return {ConvertFloatArg(v, conv, sink)};
396 }
397 
398 // ==================== Chars ====================
FormatConvertImpl(char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)399 IntegralConvertResult FormatConvertImpl(char v,
400                                         const FormatConversionSpecImpl conv,
401                                         FormatSinkImpl *sink) {
402   return {ConvertIntArg(v, conv, sink)};
403 }
FormatConvertImpl(signed char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)404 IntegralConvertResult FormatConvertImpl(signed char v,
405                                         const FormatConversionSpecImpl conv,
406                                         FormatSinkImpl *sink) {
407   return {ConvertIntArg(v, conv, sink)};
408 }
FormatConvertImpl(unsigned char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)409 IntegralConvertResult FormatConvertImpl(unsigned char v,
410                                         const FormatConversionSpecImpl conv,
411                                         FormatSinkImpl *sink) {
412   return {ConvertIntArg(v, conv, sink)};
413 }
414 
415 // ==================== Ints ====================
FormatConvertImpl(short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)416 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
417                                         const FormatConversionSpecImpl conv,
418                                         FormatSinkImpl *sink) {
419   return {ConvertIntArg(v, conv, sink)};
420 }
FormatConvertImpl(unsigned short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)421 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
422                                         const FormatConversionSpecImpl conv,
423                                         FormatSinkImpl *sink) {
424   return {ConvertIntArg(v, conv, sink)};
425 }
FormatConvertImpl(int v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)426 IntegralConvertResult FormatConvertImpl(int v,
427                                         const FormatConversionSpecImpl conv,
428                                         FormatSinkImpl *sink) {
429   return {ConvertIntArg(v, conv, sink)};
430 }
FormatConvertImpl(unsigned v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)431 IntegralConvertResult FormatConvertImpl(unsigned v,
432                                         const FormatConversionSpecImpl conv,
433                                         FormatSinkImpl *sink) {
434   return {ConvertIntArg(v, conv, sink)};
435 }
FormatConvertImpl(long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)436 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
437                                         const FormatConversionSpecImpl conv,
438                                         FormatSinkImpl *sink) {
439   return {ConvertIntArg(v, conv, sink)};
440 }
FormatConvertImpl(unsigned long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)441 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
442                                         const FormatConversionSpecImpl conv,
443                                         FormatSinkImpl *sink) {
444   return {ConvertIntArg(v, conv, sink)};
445 }
FormatConvertImpl(long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)446 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
447                                         const FormatConversionSpecImpl conv,
448                                         FormatSinkImpl *sink) {
449   return {ConvertIntArg(v, conv, sink)};
450 }
FormatConvertImpl(unsigned long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)451 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
452                                         const FormatConversionSpecImpl conv,
453                                         FormatSinkImpl *sink) {
454   return {ConvertIntArg(v, conv, sink)};
455 }
FormatConvertImpl(absl::int128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)456 IntegralConvertResult FormatConvertImpl(absl::int128 v,
457                                         const FormatConversionSpecImpl conv,
458                                         FormatSinkImpl *sink) {
459   return {ConvertIntArg(v, conv, sink)};
460 }
FormatConvertImpl(absl::uint128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)461 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
462                                         const FormatConversionSpecImpl conv,
463                                         FormatSinkImpl *sink) {
464   return {ConvertIntArg(v, conv, sink)};
465 }
466 
467 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
468 
469 
470 
471 }  // namespace str_format_internal
472 
473 ABSL_NAMESPACE_END
474 }  // namespace absl
475