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