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