Skip to content

Commit 910cc05

Browse files
committed
[libc] Better IntegerToString API
This patch is an alternative to D155902. It provides the following benefits: - No buffer manual allocation and error handling for the general case - More flexible API : width specifier, sign and prefix handling - Simpler code The more flexible API removes the need for manually tweaking the buffer afterwards, and so prevents relying on implementation details of IntegerToString. Reviewed By: michaelrj, jhuber6 Differential Revision: https://reviews.llvm.org/D156981
1 parent 2bb7272 commit 910cc05

File tree

15 files changed

+625
-521
lines changed

15 files changed

+625
-521
lines changed

libc/src/__support/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ add_header_library(
9090
HDRS
9191
integer_to_string.h
9292
DEPENDS
93+
libc.src.__support.common
94+
libc.src.__support.CPP.limits
9395
libc.src.__support.CPP.span
9496
libc.src.__support.CPP.string_view
9597
libc.src.__support.CPP.type_traits
96-
libc.src.__support.common
9798
)
9899

99100

libc/src/__support/CPP/string.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,8 @@ LIBC_INLINE string operator+(const char *lhs, const string &rhs) {
195195

196196
namespace internal {
197197
template <typename T> string to_dec_string(T value) {
198-
char dec_buf[IntegerToString::dec_bufsize<T>()];
199-
auto maybe_string_view = IntegerToString::dec(value, dec_buf);
200-
const auto &string_view = *maybe_string_view;
201-
return string(string_view.data(), string_view.size());
198+
const IntegerToString<T> buffer(value);
199+
return buffer.view();
202200
}
203201
} // namespace internal
204202

libc/src/__support/CPP/stringstream.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRINGSTREAM_H
1010
#define LLVM_LIBC_SRC_SUPPORT_CPP_STRINGSTREAM_H
1111

12-
#include "string_view.h"
1312
#include "span.h"
13+
#include "string_view.h"
1414
#include "type_traits.h"
1515

1616
#include "src/__support/integer_to_string.h"
@@ -58,11 +58,8 @@ class StringStream {
5858
// Write the |val| as string.
5959
template <typename T, enable_if_t<is_integral_v<T>, int> = 0>
6060
StringStream &operator<<(T val) {
61-
char buffer[IntegerToString::dec_bufsize<T>()];
62-
auto int_to_str = IntegerToString::dec(val, buffer);
63-
if (int_to_str)
64-
return operator<<(*int_to_str);
65-
return *this;
61+
const IntegerToString<T> buffer(val);
62+
return *this << buffer.view();
6663
}
6764

6865
template <typename T, enable_if_t<is_floating_point_v<T>, int> = 0>

libc/src/__support/FPUtil/fpbits_str.h

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818

1919
namespace __llvm_libc {
2020

21+
namespace details {
22+
23+
// Format T as uppercase hexadecimal number with leading zeros.
24+
template <typename T>
25+
using ZeroPaddedHexFmt = IntegerToString<
26+
T, typename radix::Hex::WithWidth<(sizeof(T) * 2)>::WithPrefix::Uppercase>;
27+
28+
} // namespace details
29+
2130
// Converts the bits to a string in the following format:
2231
// "0x<NNN...N> = S: N, E: 0xNNNN, M:0xNNN...N"
2332
// 1. N is a hexadecimal digit.
@@ -33,36 +42,31 @@ template <typename T> LIBC_INLINE cpp::string str(fputil::FPBits<T> x) {
3342
if (x.is_inf())
3443
return x.get_sign() ? "(-Infinity)" : "(+Infinity)";
3544

36-
auto zerofill = [](char *arr, size_t n) {
37-
for (size_t i = 0; i < n; ++i)
38-
arr[i] = '0';
39-
};
45+
const auto sign_char = [](bool sign) -> char { return sign ? '1' : '0'; };
46+
47+
cpp::string s;
4048

41-
cpp::string s("0x");
42-
char bitsbuf[IntegerToString::hex_bufsize<UIntType>()];
43-
zerofill(bitsbuf, sizeof(bitsbuf));
44-
IntegerToString::hex(x.bits, bitsbuf, false);
45-
s += cpp::string(bitsbuf, sizeof(bitsbuf));
49+
const details::ZeroPaddedHexFmt<UIntType> bits(x.bits);
50+
s += bits.view();
4651

47-
s += " = (";
48-
s += cpp::string("S: ") + (x.get_sign() ? "1" : "0");
52+
s += " = (S: ";
53+
s += sign_char(x.get_sign());
4954

50-
char expbuf[IntegerToString::hex_bufsize<uint16_t>()];
51-
zerofill(expbuf, sizeof(expbuf));
52-
IntegerToString::hex(x.get_unbiased_exponent(), expbuf, false);
53-
s += cpp::string(", E: 0x") + cpp::string(expbuf, sizeof(expbuf));
55+
s += ", E: ";
56+
const details::ZeroPaddedHexFmt<uint16_t> exponent(x.get_unbiased_exponent());
57+
s += exponent.view();
5458

5559
if constexpr (cpp::is_same_v<T, long double> &&
5660
fputil::FloatProperties<long double>::MANTISSA_WIDTH == 63) {
57-
s += cpp::string(", I: ") + (x.get_implicit_bit() ? "1" : "0");
61+
s += ", I: ";
62+
s += sign_char(x.get_implicit_bit());
5863
}
5964

60-
char mantbuf[IntegerToString::hex_bufsize<UIntType>()] = {'0'};
61-
zerofill(mantbuf, sizeof(mantbuf));
62-
IntegerToString::hex(x.get_mantissa(), mantbuf, false);
63-
s += cpp::string(", M: 0x") + cpp::string(mantbuf, sizeof(mantbuf));
65+
s += ", M: ";
66+
const details::ZeroPaddedHexFmt<UIntType> mantissa(x.get_mantissa());
67+
s += mantissa.view();
6468

65-
s += ")";
69+
s += ')';
6670
return s;
6771
}
6872

libc/src/__support/StringUtil/error_to_string.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ namespace internal {
2323

2424
constexpr size_t max_buff_size() {
2525
constexpr size_t unknown_str_len = sizeof("Unknown error");
26-
constexpr size_t max_num_len =
27-
__llvm_libc::IntegerToString::dec_bufsize<int>();
2826
// the buffer should be able to hold "Unknown error" + ' ' + num_str
29-
return (unknown_str_len + 1 + max_num_len) * sizeof(char);
27+
return (unknown_str_len + 1 + IntegerToString<int>::buffer_size()) *
28+
sizeof(char);
3029
}
3130

3231
// This is to hold error strings that have to be custom built. It may be
@@ -51,7 +50,7 @@ cpp::string_view build_error_string(int err_num, cpp::span<char> buffer) {
5150
// if the buffer can't hold "Unknown error" + ' ' + num_str, then just
5251
// return "Unknown error".
5352
if (buffer.size() <
54-
(sizeof("Unknown error") + 1 + IntegerToString::dec_bufsize<int>()))
53+
(sizeof("Unknown error") + 1 + IntegerToString<int>::buffer_size()))
5554
return const_cast<char *>("Unknown error");
5655

5756
cpp::StringStream buffer_stream(

libc/src/__support/StringUtil/signal_to_string.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ namespace internal {
2424

2525
constexpr size_t max_buff_size() {
2626
constexpr size_t base_str_len = sizeof("Real-time signal");
27-
constexpr size_t max_num_len =
28-
__llvm_libc::IntegerToString::dec_bufsize<int>();
2927
// the buffer should be able to hold "Real-time signal" + ' ' + num_str
30-
return (base_str_len + 1 + max_num_len) * sizeof(char);
28+
return (base_str_len + 1 + IntegerToString<int>::buffer_size()) *
29+
sizeof(char);
3130
}
3231

3332
// This is to hold signal strings that have to be custom built. It may be
@@ -54,7 +53,7 @@ cpp::string_view build_signal_string(int sig_num, cpp::span<char> buffer) {
5453
// if the buffer can't hold "Unknown signal" + ' ' + num_str, then just
5554
// return "Unknown signal".
5655
if (buffer.size() <
57-
(base_str.size() + 1 + IntegerToString::dec_bufsize<int>()))
56+
(base_str.size() + 1 + IntegerToString<int>::buffer_size()))
5857
return base_str;
5958

6059
cpp::StringStream buffer_stream(

0 commit comments

Comments
 (0)