1 //===-- Utilities to convert integral values to string ----------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H
10 #define LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H
14 #include "src/__support/CPP/optional.h"
15 #include "src/__support/CPP/span.h"
16 #include "src/__support/CPP/string_view.h"
17 #include "src/__support/CPP/type_traits.h"
18 #include "src/__support/common.h"
20 namespace __llvm_libc
{
22 // Convert integer values to their string representation.
27 // // Convert to hexadecimal string:
28 // char hexbuf[IntegerToString::hex_bufsize<int>()];
29 // auto str = IntegerToString::hex(
30 // a, hexbuf, false /* generate upper case characters */);
32 // // Convert to decimal string:
33 // char decbuf[IntegerToString::dec_bufsize<int>()];
34 // auto str = IntegerToString::dec(a, decbuf);
36 // // Convert to octal string:
37 // char octbuf[IntegerToString::oct_bufsize<int>(a)];
38 // auto str = IntegerToString::dec(a, octbuf);
40 // // Convert to binary string:
41 // char binbuf[IntegerToString::bin_bufsize<int>(a)];
42 // auto str = IntegerToString::bin(a, binbuf);
44 // // Convert to base 30 string:
45 // char b30buf[IntegerToString::bufsize<30, int>(a)];
46 // auto str = IntegerToString::convert<30>(a, b30buf);
47 class IntegerToString
{
48 LIBC_INLINE
static cpp::string_view
convert_uintmax(uintmax_t uval
,
49 cpp::span
<char> &buffer
,
51 const uint8_t conv_base
) {
52 const char a
= lowercase
? 'a' : 'A';
56 size_t buffptr
= buffer
.size();
58 buffer
[buffptr
- 1] = '0';
61 for (; uval
> 0; --buffptr
, uval
/= conv_base
) {
62 uintmax_t digit
= (uval
% conv_base
);
63 buffer
[buffptr
- 1] = static_cast<char>(digit
< 10 ? digit
+ '0' : digit
+ a
- 10);
66 len
= buffer
.size() - buffptr
;
68 return cpp::string_view(buffer
.data() + buffer
.size() - len
, len
);
71 LIBC_INLINE
static cpp::string_view
convert_intmax(intmax_t val
,
72 cpp::span
<char> &buffer
,
74 const uint8_t conv_base
) {
76 return convert_uintmax(uintmax_t(val
), buffer
, lowercase
, conv_base
);
77 uintmax_t uval
= uintmax_t(-val
);
78 auto str_view
= convert_uintmax(uval
, buffer
, lowercase
, conv_base
);
79 size_t len
= str_view
.size();
81 buffer
[buffer
.size() - len
] = '-';
82 return cpp::string_view(buffer
.data() + buffer
.size() - len
, len
);
85 LIBC_INLINE
static constexpr size_t floor_log_2(size_t num
) {
87 for (; num
> 1; num
/= 2) {
94 // We size the string buffer for base 10 using an approximation algorithm:
96 // size = ceil(sizeof(T) * 5 / 2)
98 // If sizeof(T) is 1, then size is 3 (actually need 3)
99 // If sizeof(T) is 2, then size is 5 (actually need 5)
100 // If sizeof(T) is 4, then size is 10 (actually need 10)
101 // If sizeof(T) is 8, then size is 20 (actually need 20)
102 // If sizeof(T) is 16, then size is 40 (actually need 39)
104 // NOTE: The ceil operation is actually implemented as
105 // floor(((sizeof(T) * 5) + 1)/2)
106 // where floor operation is just integer division.
108 // This estimation grows slightly faster than the actual value, but the
109 // overhead is small enough to tolerate. In the actual formula below, we
110 // add an additional byte to accommodate the '-' sign in case of signed
112 // For other bases, we approximate by rounding down to the nearest power of
113 // two base, since the space needed is easy to calculate and it won't
114 // overestimate by too much.
115 template <uint8_t BASE
, typename T
>
116 LIBC_INLINE
static constexpr size_t bufsize() {
117 constexpr size_t BITS_PER_DIGIT
= floor_log_2(BASE
);
118 constexpr size_t BUFSIZE_COMMON
=
119 ((sizeof(T
) * 8 + (BITS_PER_DIGIT
- 1)) / BITS_PER_DIGIT
);
120 constexpr size_t BUFSIZE_BASE10
= (sizeof(T
) * 5 + 1) / 2;
121 return (cpp::is_signed
<T
>() ? 1 : 0) +
122 (BASE
== 10 ? BUFSIZE_BASE10
: BUFSIZE_COMMON
);
125 template <typename T
> LIBC_INLINE
static constexpr size_t dec_bufsize() {
126 return bufsize
<10, T
>();
129 template <typename T
> LIBC_INLINE
static constexpr size_t hex_bufsize() {
130 return bufsize
<16, T
>();
133 template <typename T
> LIBC_INLINE
static constexpr size_t oct_bufsize() {
134 return bufsize
<8, T
>();
137 template <typename T
> LIBC_INLINE
static constexpr size_t bin_bufsize() {
138 return bufsize
<2, T
>();
141 template <uint8_t BASE
, typename T
,
142 cpp::enable_if_t
<2 <= BASE
&& BASE
<= 36 && cpp::is_integral_v
<T
>,
144 LIBC_INLINE
static cpp::optional
<cpp::string_view
>
145 convert(T val
, cpp::span
<char> buffer
, bool lowercase
= true) {
146 if (buffer
.size() < bufsize
<BASE
, T
>())
147 return cpp::optional
<cpp::string_view
>();
148 if (cpp::is_signed_v
<T
>)
149 return convert_intmax(intmax_t(val
), buffer
, lowercase
, BASE
);
151 return convert_uintmax(uintmax_t(val
), buffer
, lowercase
, BASE
);
154 template <typename T
, cpp::enable_if_t
<cpp::is_integral_v
<T
>, int> = 0>
155 LIBC_INLINE
static cpp::optional
<cpp::string_view
>
156 dec(T val
, cpp::span
<char> buffer
) {
157 return convert
<10>(val
, buffer
);
160 template <typename T
, cpp::enable_if_t
<cpp::is_integral_v
<T
>, int> = 0>
161 LIBC_INLINE
static cpp::optional
<cpp::string_view
>
162 hex(T val
, cpp::span
<char> buffer
, bool lowercase
= true) {
163 return convert
<16>(val
, buffer
, lowercase
);
166 template <typename T
, cpp::enable_if_t
<cpp::is_integral_v
<T
>, int> = 0>
167 LIBC_INLINE
static cpp::optional
<cpp::string_view
>
168 oct(T val
, cpp::span
<char> buffer
) {
169 return convert
<8>(val
, buffer
);
172 template <typename T
, cpp::enable_if_t
<cpp::is_integral_v
<T
>, int> = 0>
173 LIBC_INLINE
static cpp::optional
<cpp::string_view
>
174 bin(T val
, cpp::span
<char> buffer
) {
175 return convert
<2>(val
, buffer
);
179 } // namespace __llvm_libc
181 #endif // LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H