xref: /aosp_15_r20/external/abseil-cpp/absl/strings/internal/str_format/arg.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //
16 // POSIX spec:
17 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
18 //
19 #include "absl/strings/internal/str_format/arg.h"
20 
21 #include <algorithm>
22 #include <cassert>
23 #include <cstddef>
24 #include <cstdint>
25 #include <cstdlib>
26 #include <cstring>
27 #include <cwchar>
28 #include <string>
29 #include <type_traits>
30 
31 #include "absl/base/config.h"
32 #include "absl/base/optimization.h"
33 #include "absl/container/fixed_array.h"
34 #include "absl/numeric/int128.h"
35 #include "absl/strings/internal/str_format/extension.h"
36 #include "absl/strings/internal/str_format/float_conversion.h"
37 #include "absl/strings/numbers.h"
38 #include "absl/strings/string_view.h"
39 
40 #if defined(ABSL_HAVE_STD_STRING_VIEW)
41 #include <string_view>
42 #endif
43 
44 namespace absl {
45 ABSL_NAMESPACE_BEGIN
46 namespace str_format_internal {
47 namespace {
48 
49 // Reduce *capacity by s.size(), clipped to a 0 minimum.
ReducePadding(string_view s,size_t * capacity)50 void ReducePadding(string_view s, size_t *capacity) {
51   *capacity = Excess(s.size(), *capacity);
52 }
53 
54 // Reduce *capacity by n, clipped to a 0 minimum.
ReducePadding(size_t n,size_t * capacity)55 void ReducePadding(size_t n, size_t *capacity) {
56   *capacity = Excess(n, *capacity);
57 }
58 
59 template <typename T>
60 struct MakeUnsigned : std::make_unsigned<T> {};
61 template <>
62 struct MakeUnsigned<absl::int128> {
63   using type = absl::uint128;
64 };
65 template <>
66 struct MakeUnsigned<absl::uint128> {
67   using type = absl::uint128;
68 };
69 
70 template <typename T>
71 struct IsSigned : std::is_signed<T> {};
72 template <>
73 struct IsSigned<absl::int128> : std::true_type {};
74 template <>
75 struct IsSigned<absl::uint128> : std::false_type {};
76 
77 // Integral digit printer.
78 // Call one of the PrintAs* routines after construction once.
79 // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
80 class IntDigits {
81  public:
82   // Print the unsigned integer as octal.
83   // Supports unsigned integral types and uint128.
84   template <typename T>
PrintAsOct(T v)85   void PrintAsOct(T v) {
86     static_assert(!IsSigned<T>::value, "");
87     char *p = storage_ + sizeof(storage_);
88     do {
89       *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
90       v >>= 3;
91     } while (v);
92     start_ = p;
93     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
94   }
95 
96   // Print the signed or unsigned integer as decimal.
97   // Supports all integral types.
98   template <typename T>
PrintAsDec(T v)99   void PrintAsDec(T v) {
100     static_assert(std::is_integral<T>::value, "");
101     start_ = storage_;
102     size_ = static_cast<size_t>(numbers_internal::FastIntToBuffer(v, storage_) -
103                                 storage_);
104   }
105 
PrintAsDec(int128 v)106   void PrintAsDec(int128 v) {
107     auto u = static_cast<uint128>(v);
108     bool add_neg = false;
109     if (v < 0) {
110       add_neg = true;
111       u = uint128{} - u;
112     }
113     PrintAsDec(u, add_neg);
114   }
115 
PrintAsDec(uint128 v,bool add_neg=false)116   void PrintAsDec(uint128 v, bool add_neg = false) {
117     // This function can be sped up if needed. We can call FastIntToBuffer
118     // twice, or fix FastIntToBuffer to support uint128.
119     char *p = storage_ + sizeof(storage_);
120     do {
121       p -= 2;
122       numbers_internal::PutTwoDigits(static_cast<uint32_t>(v % 100), p);
123       v /= 100;
124     } while (v);
125     if (p[0] == '0') {
126       // We printed one too many hexits.
127       ++p;
128     }
129     if (add_neg) {
130       *--p = '-';
131     }
132     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
133     start_ = p;
134   }
135 
136   // Print the unsigned integer as hex using lowercase.
137   // Supports unsigned integral types and uint128.
138   template <typename T>
PrintAsHexLower(T v)139   void PrintAsHexLower(T v) {
140     static_assert(!IsSigned<T>::value, "");
141     char *p = storage_ + sizeof(storage_);
142 
143     do {
144       p -= 2;
145       constexpr const char* table = numbers_internal::kHexTable;
146       std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
147       if (sizeof(T) == 1) break;
148       v >>= 8;
149     } while (v);
150     if (p[0] == '0') {
151       // We printed one too many digits.
152       ++p;
153     }
154     start_ = p;
155     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
156   }
157 
158   // Print the unsigned integer as hex using uppercase.
159   // Supports unsigned integral types and uint128.
160   template <typename T>
PrintAsHexUpper(T v)161   void PrintAsHexUpper(T v) {
162     static_assert(!IsSigned<T>::value, "");
163     char *p = storage_ + sizeof(storage_);
164 
165     // kHexTable is only lowercase, so do it manually for uppercase.
166     do {
167       *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
168       v >>= 4;
169     } while (v);
170     start_ = p;
171     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
172   }
173 
174   // The printed value including the '-' sign if available.
175   // For inputs of value `0`, this will return "0"
with_neg_and_zero() const176   string_view with_neg_and_zero() const { return {start_, size_}; }
177 
178   // The printed value not including the '-' sign.
179   // For inputs of value `0`, this will return "".
without_neg_or_zero() const180   string_view without_neg_or_zero() const {
181     static_assert('-' < '0', "The check below verifies both.");
182     size_t advance = start_[0] <= '0' ? 1 : 0;
183     return {start_ + advance, size_ - advance};
184   }
185 
is_negative() const186   bool is_negative() const { return start_[0] == '-'; }
187 
188  private:
189   const char *start_;
190   size_t size_;
191   // Max size: 128 bit value as octal -> 43 digits, plus sign char
192   char storage_[128 / 3 + 1 + 1];
193 };
194 
195 // Note: 'o' conversions do not have a base indicator, it's just that
196 // the '#' flag is specified to modify the precision for 'o' conversions.
BaseIndicator(const IntDigits & as_digits,const FormatConversionSpecImpl conv)197 string_view BaseIndicator(const IntDigits &as_digits,
198                           const FormatConversionSpecImpl conv) {
199   // always show 0x for %p.
200   bool alt = conv.has_alt_flag() ||
201              conv.conversion_char() == FormatConversionCharInternal::p;
202   bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
203               conv.conversion_char() == FormatConversionCharInternal::X ||
204               conv.conversion_char() == FormatConversionCharInternal::p);
205   // From the POSIX description of '#' flag:
206   //   "For x or X conversion specifiers, a non-zero result shall have
207   //   0x (or 0X) prefixed to it."
208   if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
209     return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
210                                                                      : "0x";
211   }
212   return {};
213 }
214 
SignColumn(bool neg,const FormatConversionSpecImpl conv)215 string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
216   if (conv.conversion_char() == FormatConversionCharInternal::d ||
217       conv.conversion_char() == FormatConversionCharInternal::i) {
218     if (neg) return "-";
219     if (conv.has_show_pos_flag()) return "+";
220     if (conv.has_sign_col_flag()) return " ";
221   }
222   return {};
223 }
224 
ConvertCharImpl(char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)225 bool ConvertCharImpl(char v,
226                      const FormatConversionSpecImpl conv,
227                      FormatSinkImpl* sink) {
228   size_t fill = 0;
229   if (conv.width() >= 0)
230     fill = static_cast<size_t>(conv.width());
231   ReducePadding(1, &fill);
232   if (!conv.has_left_flag()) sink->Append(fill, ' ');
233   sink->Append(1, v);
234   if (conv.has_left_flag()) sink->Append(fill, ' ');
235   return true;
236 }
237 
ConvertIntImplInnerSlow(const IntDigits & as_digits,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)238 bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
239                              const FormatConversionSpecImpl conv,
240                              FormatSinkImpl *sink) {
241   // Print as a sequence of Substrings:
242   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
243   size_t fill = 0;
244   if (conv.width() >= 0)
245     fill = static_cast<size_t>(conv.width());
246 
247   string_view formatted = as_digits.without_neg_or_zero();
248   ReducePadding(formatted, &fill);
249 
250   string_view sign = SignColumn(as_digits.is_negative(), conv);
251   ReducePadding(sign, &fill);
252 
253   string_view base_indicator = BaseIndicator(as_digits, conv);
254   ReducePadding(base_indicator, &fill);
255 
256   bool precision_specified = conv.precision() >= 0;
257   size_t precision =
258       precision_specified ? static_cast<size_t>(conv.precision()) : size_t{1};
259 
260   if (conv.has_alt_flag() &&
261       conv.conversion_char() == FormatConversionCharInternal::o) {
262     // From POSIX description of the '#' (alt) flag:
263     //   "For o conversion, it increases the precision (if necessary) to
264     //   force the first digit of the result to be zero."
265     if (formatted.empty() || *formatted.begin() != '0') {
266       size_t needed = formatted.size() + 1;
267       precision = std::max(precision, needed);
268     }
269   }
270 
271   size_t num_zeroes = Excess(formatted.size(), precision);
272   ReducePadding(num_zeroes, &fill);
273 
274   size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
275   size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
276 
277   // From POSIX description of the '0' (zero) flag:
278   //   "For d, i, o, u, x, and X conversion specifiers, if a precision
279   //   is specified, the '0' flag is ignored."
280   if (!precision_specified && conv.has_zero_flag()) {
281     num_zeroes += num_left_spaces;
282     num_left_spaces = 0;
283   }
284 
285   sink->Append(num_left_spaces, ' ');
286   sink->Append(sign);
287   sink->Append(base_indicator);
288   sink->Append(num_zeroes, '0');
289   sink->Append(formatted);
290   sink->Append(num_right_spaces, ' ');
291   return true;
292 }
293 
294 template <typename T>
ConvertFloatArg(T v,FormatConversionSpecImpl conv,FormatSinkImpl * sink)295 bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
296   if (conv.conversion_char() == FormatConversionCharInternal::v) {
297     conv.set_conversion_char(FormatConversionCharInternal::g);
298   }
299 
300   return FormatConversionCharIsFloat(conv.conversion_char()) &&
301          ConvertFloatImpl(v, conv, sink);
302 }
303 
ConvertStringArg(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)304 inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
305                              FormatSinkImpl *sink) {
306   if (conv.is_basic()) {
307     sink->Append(v);
308     return true;
309   }
310   return sink->PutPaddedString(v, conv.width(), conv.precision(),
311                                conv.has_left_flag());
312 }
313 
314 struct ShiftState {
315   bool saw_high_surrogate = false;
316   uint8_t bits = 0;
317 };
318 
319 // Converts `v` from UTF-16 or UTF-32 to UTF-8 and writes to `buf`. `buf` is
320 // assumed to have enough space for the output. `s` is used to carry state
321 // between successive calls with a UTF-16 surrogate pair. Returns the number of
322 // chars written, or `static_cast<size_t>(-1)` on failure.
323 //
324 // This is basically std::wcrtomb(), but always outputting UTF-8 instead of
325 // respecting the current locale.
WideToUtf8(wchar_t wc,char * buf,ShiftState & s)326 inline size_t WideToUtf8(wchar_t wc, char *buf, ShiftState &s) {
327   const auto v = static_cast<uint32_t>(wc);
328   if (v < 0x80) {
329     *buf = static_cast<char>(v);
330     return 1;
331   } else if (v < 0x800) {
332     *buf++ = static_cast<char>(0xc0 | (v >> 6));
333     *buf = static_cast<char>(0x80 | (v & 0x3f));
334     return 2;
335   } else if (v < 0xd800 || (v - 0xe000) < 0x2000) {
336     *buf++ = static_cast<char>(0xe0 | (v >> 12));
337     *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
338     *buf = static_cast<char>(0x80 | (v & 0x3f));
339     return 3;
340   } else if ((v - 0x10000) < 0x100000) {
341     *buf++ = static_cast<char>(0xf0 | (v >> 18));
342     *buf++ = static_cast<char>(0x80 | ((v >> 12) & 0x3f));
343     *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
344     *buf = static_cast<char>(0x80 | (v & 0x3f));
345     return 4;
346   } else if (v < 0xdc00) {
347     s.saw_high_surrogate = true;
348     s.bits = static_cast<uint8_t>(v & 0x3);
349     const uint8_t high_bits = ((v >> 6) & 0xf) + 1;
350     *buf++ = static_cast<char>(0xf0 | (high_bits >> 2));
351     *buf =
352         static_cast<char>(0x80 | static_cast<uint8_t>((high_bits & 0x3) << 4) |
353                           static_cast<uint8_t>((v >> 2) & 0xf));
354     return 2;
355   } else if (v < 0xe000 && s.saw_high_surrogate) {
356     *buf++ = static_cast<char>(0x80 | static_cast<uint8_t>(s.bits << 4) |
357                                static_cast<uint8_t>((v >> 6) & 0xf));
358     *buf = static_cast<char>(0x80 | (v & 0x3f));
359     s.saw_high_surrogate = false;
360     s.bits = 0;
361     return 2;
362   } else {
363     return static_cast<size_t>(-1);
364   }
365 }
366 
ConvertStringArg(const wchar_t * v,size_t len,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)367 inline bool ConvertStringArg(const wchar_t *v,
368                              size_t len,
369                              const FormatConversionSpecImpl conv,
370                              FormatSinkImpl *sink) {
371   FixedArray<char> mb(len * 4);
372   ShiftState s;
373   size_t chars_written = 0;
374   for (size_t i = 0; i < len; ++i) {
375     const size_t chars = WideToUtf8(v[i], &mb[chars_written], s);
376     if (chars == static_cast<size_t>(-1)) { return false; }
377     chars_written += chars;
378   }
379   return ConvertStringArg(string_view(mb.data(), chars_written), conv, sink);
380 }
381 
ConvertWCharTImpl(wchar_t v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)382 bool ConvertWCharTImpl(wchar_t v, const FormatConversionSpecImpl conv,
383                        FormatSinkImpl *sink) {
384   char mb[4];
385   ShiftState s;
386   const size_t chars_written = WideToUtf8(v, mb, s);
387   return chars_written != static_cast<size_t>(-1) && !s.saw_high_surrogate &&
388          ConvertStringArg(string_view(mb, chars_written), conv, sink);
389 }
390 
391 }  // namespace
392 
ConvertBoolArg(bool v,FormatSinkImpl * sink)393 bool ConvertBoolArg(bool v, FormatSinkImpl *sink) {
394   if (v) {
395     sink->Append("true");
396   } else {
397     sink->Append("false");
398   }
399   return true;
400 }
401 
402 template <typename T>
ConvertIntArg(T v,FormatConversionSpecImpl conv,FormatSinkImpl * sink)403 bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
404   using U = typename MakeUnsigned<T>::type;
405   IntDigits as_digits;
406 
407   // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
408   // it to complain about a switch/case type mismatch, even though both are
409   // FormatConversionChar.  Likely this is because at this point
410   // FormatConversionChar is declared, but not defined.
411   switch (static_cast<uint8_t>(conv.conversion_char())) {
412     case static_cast<uint8_t>(FormatConversionCharInternal::c):
413       return (std::is_same<T, wchar_t>::value ||
414               (conv.length_mod() == LengthMod::l))
415                  ? ConvertWCharTImpl(static_cast<wchar_t>(v), conv, sink)
416                  : ConvertCharImpl(static_cast<char>(v), conv, sink);
417 
418     case static_cast<uint8_t>(FormatConversionCharInternal::o):
419       as_digits.PrintAsOct(static_cast<U>(v));
420       break;
421 
422     case static_cast<uint8_t>(FormatConversionCharInternal::x):
423       as_digits.PrintAsHexLower(static_cast<U>(v));
424       break;
425     case static_cast<uint8_t>(FormatConversionCharInternal::X):
426       as_digits.PrintAsHexUpper(static_cast<U>(v));
427       break;
428 
429     case static_cast<uint8_t>(FormatConversionCharInternal::u):
430       as_digits.PrintAsDec(static_cast<U>(v));
431       break;
432 
433     case static_cast<uint8_t>(FormatConversionCharInternal::d):
434     case static_cast<uint8_t>(FormatConversionCharInternal::i):
435     case static_cast<uint8_t>(FormatConversionCharInternal::v):
436       as_digits.PrintAsDec(v);
437       break;
438 
439     case static_cast<uint8_t>(FormatConversionCharInternal::a):
440     case static_cast<uint8_t>(FormatConversionCharInternal::e):
441     case static_cast<uint8_t>(FormatConversionCharInternal::f):
442     case static_cast<uint8_t>(FormatConversionCharInternal::g):
443     case static_cast<uint8_t>(FormatConversionCharInternal::A):
444     case static_cast<uint8_t>(FormatConversionCharInternal::E):
445     case static_cast<uint8_t>(FormatConversionCharInternal::F):
446     case static_cast<uint8_t>(FormatConversionCharInternal::G):
447       return ConvertFloatImpl(static_cast<double>(v), conv, sink);
448 
449     default:
450       ABSL_ASSUME(false);
451   }
452 
453   if (conv.is_basic()) {
454     sink->Append(as_digits.with_neg_and_zero());
455     return true;
456   }
457   return ConvertIntImplInnerSlow(as_digits, conv, sink);
458 }
459 
460 template bool ConvertIntArg<char>(char v, FormatConversionSpecImpl conv,
461                                   FormatSinkImpl *sink);
462 template bool ConvertIntArg<signed char>(signed char v,
463                                          FormatConversionSpecImpl conv,
464                                          FormatSinkImpl *sink);
465 template bool ConvertIntArg<unsigned char>(unsigned char v,
466                                            FormatConversionSpecImpl conv,
467                                            FormatSinkImpl *sink);
468 template bool ConvertIntArg<wchar_t>(wchar_t v, FormatConversionSpecImpl conv,
469                                      FormatSinkImpl *sink);
470 template bool ConvertIntArg<short>(short v,  // NOLINT
471                                    FormatConversionSpecImpl conv,
472                                    FormatSinkImpl *sink);
473 template bool ConvertIntArg<unsigned short>(unsigned short v,  // NOLINT
474                                             FormatConversionSpecImpl conv,
475                                             FormatSinkImpl *sink);
476 template bool ConvertIntArg<int>(int v, FormatConversionSpecImpl conv,
477                                  FormatSinkImpl *sink);
478 template bool ConvertIntArg<unsigned int>(unsigned int v,
479                                           FormatConversionSpecImpl conv,
480                                           FormatSinkImpl *sink);
481 template bool ConvertIntArg<long>(long v,  // NOLINT
482                                   FormatConversionSpecImpl conv,
483                                   FormatSinkImpl *sink);
484 template bool ConvertIntArg<unsigned long>(unsigned long v,  // NOLINT
485                                            FormatConversionSpecImpl conv,
486                                            FormatSinkImpl *sink);
487 template bool ConvertIntArg<long long>(long long v,  // NOLINT
488                                        FormatConversionSpecImpl conv,
489                                        FormatSinkImpl *sink);
490 template bool ConvertIntArg<unsigned long long>(unsigned long long v,  // NOLINT
491                                                 FormatConversionSpecImpl conv,
492                                                 FormatSinkImpl *sink);
493 
494 // ==================== Strings ====================
FormatConvertImpl(const std::string & v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)495 StringConvertResult FormatConvertImpl(const std::string &v,
496                                       const FormatConversionSpecImpl conv,
497                                       FormatSinkImpl *sink) {
498   return {ConvertStringArg(v, conv, sink)};
499 }
500 
FormatConvertImpl(const std::wstring & v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)501 StringConvertResult FormatConvertImpl(const std::wstring &v,
502                                       const FormatConversionSpecImpl conv,
503                                       FormatSinkImpl *sink) {
504   return {ConvertStringArg(v.data(), v.size(), conv, sink)};
505 }
506 
FormatConvertImpl(string_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)507 StringConvertResult FormatConvertImpl(string_view v,
508                                       const FormatConversionSpecImpl conv,
509                                       FormatSinkImpl *sink) {
510   return {ConvertStringArg(v, conv, sink)};
511 }
512 
513 #if defined(ABSL_HAVE_STD_STRING_VIEW)
FormatConvertImpl(std::wstring_view v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)514 StringConvertResult FormatConvertImpl(std::wstring_view v,
515                                       const FormatConversionSpecImpl conv,
516                                       FormatSinkImpl* sink) {
517   return {ConvertStringArg(v.data(), v.size(), conv, sink)};
518 }
519 #endif
520 
FormatConvertImpl(const char * v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)521 StringPtrConvertResult FormatConvertImpl(const char* v,
522                                          const FormatConversionSpecImpl conv,
523                                          FormatSinkImpl* sink) {
524   if (conv.conversion_char() == FormatConversionCharInternal::p)
525     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
526   size_t len;
527   if (v == nullptr) {
528     len = 0;
529   } else if (conv.precision() < 0) {
530     len = std::strlen(v);
531   } else {
532     // If precision is set, we look for the NUL-terminator on the valid range.
533     len = static_cast<size_t>(std::find(v, v + conv.precision(), '\0') - v);
534   }
535   return {ConvertStringArg(string_view(v, len), conv, sink)};
536 }
537 
FormatConvertImpl(const wchar_t * v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)538 StringPtrConvertResult FormatConvertImpl(const wchar_t* v,
539                                          const FormatConversionSpecImpl conv,
540                                          FormatSinkImpl* sink) {
541   if (conv.conversion_char() == FormatConversionCharInternal::p) {
542     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
543   }
544   size_t len;
545   if (v == nullptr) {
546     len = 0;
547   } else if (conv.precision() < 0) {
548     len = std::wcslen(v);
549   } else {
550     // If precision is set, we look for the NUL-terminator on the valid range.
551     len = static_cast<size_t>(std::find(v, v + conv.precision(), L'\0') - v);
552   }
553   return {ConvertStringArg(v, len, conv, sink)};
554 }
555 
FormatConvertImpl(std::nullptr_t,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)556 StringPtrConvertResult FormatConvertImpl(std::nullptr_t,
557                                          const FormatConversionSpecImpl conv,
558                                          FormatSinkImpl* sink) {
559   return FormatConvertImpl(static_cast<const char*>(nullptr), conv, sink);
560 }
561 
562 // ==================== Raw pointers ====================
FormatConvertImpl(VoidPtr v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)563 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
564     VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
565   if (!v.value) {
566     sink->Append("(nil)");
567     return {true};
568   }
569   IntDigits as_digits;
570   as_digits.PrintAsHexLower(v.value);
571   return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
572 }
573 
574 // ==================== Floats ====================
FormatConvertImpl(float v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)575 FloatingConvertResult FormatConvertImpl(float v,
576                                         const FormatConversionSpecImpl conv,
577                                         FormatSinkImpl *sink) {
578   return {ConvertFloatArg(v, conv, sink)};
579 }
FormatConvertImpl(double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)580 FloatingConvertResult FormatConvertImpl(double v,
581                                         const FormatConversionSpecImpl conv,
582                                         FormatSinkImpl *sink) {
583   return {ConvertFloatArg(v, conv, sink)};
584 }
FormatConvertImpl(long double v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)585 FloatingConvertResult FormatConvertImpl(long double v,
586                                         const FormatConversionSpecImpl conv,
587                                         FormatSinkImpl *sink) {
588   return {ConvertFloatArg(v, conv, sink)};
589 }
590 
591 // ==================== Chars ====================
FormatConvertImpl(char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)592 CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
593                                     FormatSinkImpl *sink) {
594   return {ConvertIntArg(v, conv, sink)};
595 }
FormatConvertImpl(wchar_t v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)596 CharConvertResult FormatConvertImpl(wchar_t v,
597                                     const FormatConversionSpecImpl conv,
598                                     FormatSinkImpl* sink) {
599   return {ConvertIntArg(v, conv, sink)};
600 }
601 
602 // ==================== Ints ====================
FormatConvertImpl(signed char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)603 IntegralConvertResult FormatConvertImpl(signed char v,
604                                         const FormatConversionSpecImpl conv,
605                                         FormatSinkImpl *sink) {
606   return {ConvertIntArg(v, conv, sink)};
607 }
FormatConvertImpl(unsigned char v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)608 IntegralConvertResult FormatConvertImpl(unsigned char v,
609                                         const FormatConversionSpecImpl conv,
610                                         FormatSinkImpl *sink) {
611   return {ConvertIntArg(v, conv, sink)};
612 }
FormatConvertImpl(short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)613 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
614                                         const FormatConversionSpecImpl conv,
615                                         FormatSinkImpl *sink) {
616   return {ConvertIntArg(v, conv, sink)};
617 }
FormatConvertImpl(unsigned short v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)618 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
619                                         const FormatConversionSpecImpl conv,
620                                         FormatSinkImpl *sink) {
621   return {ConvertIntArg(v, conv, sink)};
622 }
FormatConvertImpl(int v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)623 IntegralConvertResult FormatConvertImpl(int v,
624                                         const FormatConversionSpecImpl conv,
625                                         FormatSinkImpl *sink) {
626   return {ConvertIntArg(v, conv, sink)};
627 }
FormatConvertImpl(unsigned v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)628 IntegralConvertResult FormatConvertImpl(unsigned v,
629                                         const FormatConversionSpecImpl conv,
630                                         FormatSinkImpl *sink) {
631   return {ConvertIntArg(v, conv, sink)};
632 }
FormatConvertImpl(long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)633 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
634                                         const FormatConversionSpecImpl conv,
635                                         FormatSinkImpl *sink) {
636   return {ConvertIntArg(v, conv, sink)};
637 }
FormatConvertImpl(unsigned long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)638 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
639                                         const FormatConversionSpecImpl conv,
640                                         FormatSinkImpl *sink) {
641   return {ConvertIntArg(v, conv, sink)};
642 }
FormatConvertImpl(long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)643 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
644                                         const FormatConversionSpecImpl conv,
645                                         FormatSinkImpl *sink) {
646   return {ConvertIntArg(v, conv, sink)};
647 }
FormatConvertImpl(unsigned long long v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)648 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
649                                         const FormatConversionSpecImpl conv,
650                                         FormatSinkImpl *sink) {
651   return {ConvertIntArg(v, conv, sink)};
652 }
FormatConvertImpl(absl::int128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)653 IntegralConvertResult FormatConvertImpl(absl::int128 v,
654                                         const FormatConversionSpecImpl conv,
655                                         FormatSinkImpl *sink) {
656   return {ConvertIntArg(v, conv, sink)};
657 }
FormatConvertImpl(absl::uint128 v,const FormatConversionSpecImpl conv,FormatSinkImpl * sink)658 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
659                                         const FormatConversionSpecImpl conv,
660                                         FormatSinkImpl *sink) {
661   return {ConvertIntArg(v, conv, sink)};
662 }
663 
664 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
665 
666 
667 
668 }  // namespace str_format_internal
669 
670 ABSL_NAMESPACE_END
671 }  // namespace absl
672