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