1 //===-- Hexadecimal Converter for printf ------------------------*- 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_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
12 #include "src/__support/CPP/string_view.h"
13 #include "src/__support/FPUtil/FPBits.h"
14 #include "src/__support/FPUtil/rounding_mode.h"
15 #include "src/__support/macros/config.h"
16 #include "src/stdio/printf_core/converter_utils.h"
17 #include "src/stdio/printf_core/core_structs.h"
18 #include "src/stdio/printf_core/float_inf_nan_converter.h"
19 #include "src/stdio/printf_core/writer.h"
24 namespace LIBC_NAMESPACE_DECL
{
25 namespace printf_core
{
27 LIBC_INLINE
int convert_float_hex_exp(Writer
*writer
,
28 const FormatSection
&to_conv
) {
29 using LDBits
= fputil::FPBits
<long double>;
30 using StorageType
= LDBits::StorageType
;
31 // All of the letters will be defined relative to variable a, which will be
32 // the appropriate case based on the name of the conversion. This converts any
33 // conversion name into the letter 'a' with the appropriate case.
34 const char a
= (to_conv
.conv_name
& 32) | 'A';
40 uint32_t fraction_bits
;
41 if (to_conv
.length_modifier
== LengthModifier::L
) {
42 fraction_bits
= LDBits::FRACTION_LEN
;
43 LDBits::StorageType float_raw
= to_conv
.conv_val_raw
;
44 LDBits
float_bits(float_raw
);
45 is_negative
= float_bits
.is_neg();
46 exponent
= float_bits
.get_explicit_exponent();
47 mantissa
= float_bits
.get_explicit_mantissa();
48 is_inf_or_nan
= float_bits
.is_inf_or_nan();
50 using LBits
= fputil::FPBits
<double>;
51 fraction_bits
= LBits::FRACTION_LEN
;
52 LBits::StorageType float_raw
=
53 static_cast<LBits::StorageType
>(to_conv
.conv_val_raw
);
54 LBits
float_bits(float_raw
);
55 is_negative
= float_bits
.is_neg();
56 exponent
= float_bits
.get_explicit_exponent();
57 mantissa
= float_bits
.get_explicit_mantissa();
58 is_inf_or_nan
= float_bits
.is_inf_or_nan();
62 return convert_inf_nan(writer
, to_conv
);
68 else if ((to_conv
.flags
& FormatFlags::FORCE_SIGN
) == FormatFlags::FORCE_SIGN
)
69 sign_char
= '+'; // FORCE_SIGN has precedence over SPACE_PREFIX
70 else if ((to_conv
.flags
& FormatFlags::SPACE_PREFIX
) ==
71 FormatFlags::SPACE_PREFIX
)
74 constexpr size_t BITS_IN_HEX_DIGIT
= 4;
76 // This is to handle situations where the mantissa isn't an even number of hex
77 // digits. This is primarily relevant for x86 80 bit long doubles, which have
78 // 63 bit mantissas. In the case where the mantissa is 0, however, the
79 // exponent should stay as 0.
80 if (fraction_bits
% BITS_IN_HEX_DIGIT
!= 0 && mantissa
> 0) {
81 exponent
-= fraction_bits
% BITS_IN_HEX_DIGIT
;
84 // This is the max number of digits it can take to represent the mantissa.
85 // Since the number is in bits, we divide by 4, and then add one to account
86 // for the extra implicit bit. We use the larger of the two possible values
87 // since the size must be constant.
88 constexpr size_t MANT_BUFF_LEN
=
89 (LDBits::FRACTION_LEN
/ BITS_IN_HEX_DIGIT
) + 1;
90 char mant_buffer
[MANT_BUFF_LEN
];
92 size_t mant_len
= (fraction_bits
/ BITS_IN_HEX_DIGIT
) + 1;
94 // Precision only tracks the number of digits after the hexadecimal point, so
95 // we have to add one to account for the digit before the hexadecimal point.
96 if (to_conv
.precision
+ 1 < static_cast<int>(mant_len
) &&
97 to_conv
.precision
+ 1 > 0) {
98 const size_t intended_digits
= to_conv
.precision
+ 1;
99 const size_t shift_amount
=
100 (mant_len
- intended_digits
) * BITS_IN_HEX_DIGIT
;
102 const StorageType truncated_bits
=
103 mantissa
& ((StorageType(1) << shift_amount
) - 1);
104 const StorageType halfway_const
= StorageType(1) << (shift_amount
- 1);
106 mantissa
>>= shift_amount
;
108 switch (fputil::quick_get_round()) {
110 // Round to nearest, if it's exactly halfway then round to even.
111 if (truncated_bits
> halfway_const
)
113 else if (truncated_bits
== halfway_const
)
114 mantissa
= mantissa
+ (mantissa
& 1);
117 if (truncated_bits
> 0 && is_negative
)
121 if (truncated_bits
> 0 && !is_negative
)
128 // If the rounding caused an overflow, shift the mantissa and adjust the
129 // exponent to match.
130 if (mantissa
>= (StorageType(1) << (intended_digits
* BITS_IN_HEX_DIGIT
))) {
131 mantissa
>>= BITS_IN_HEX_DIGIT
;
132 exponent
+= BITS_IN_HEX_DIGIT
;
135 mant_len
= intended_digits
;
138 size_t mant_cur
= mant_len
;
139 size_t first_non_zero
= 1;
140 for (; mant_cur
> 0; --mant_cur
, mantissa
>>= 4) {
141 char mant_mod_16
= static_cast<char>(mantissa
) & 15;
142 char new_digit
= static_cast<char>(
143 (mant_mod_16
> 9) ? (mant_mod_16
- 10 + a
) : (mant_mod_16
+ '0'));
144 mant_buffer
[mant_cur
- 1] = new_digit
;
145 if (new_digit
!= '0' && first_non_zero
< mant_cur
)
146 first_non_zero
= mant_cur
;
149 size_t mant_digits
= first_non_zero
;
150 if (to_conv
.precision
>= 0)
151 mant_digits
= mant_len
;
153 // This approximates the number of digits it will take to represent the
154 // exponent. The calculation is ceil((bits * 5) / 16). Floor also works, but
155 // only on exact multiples of 16. We add 1 for the sign.
160 constexpr size_t EXP_LEN
= (((LDBits::EXP_LEN
* 5) + 15) / 16) + 1;
161 char exp_buffer
[EXP_LEN
];
163 bool exp_is_negative
= false;
165 exp_is_negative
= true;
166 exponent
= -exponent
;
169 size_t exp_cur
= EXP_LEN
;
170 for (; exponent
> 0; --exp_cur
, exponent
/= 10) {
171 exp_buffer
[exp_cur
- 1] = static_cast<char>((exponent
% 10) + '0');
173 if (exp_cur
== EXP_LEN
) { // if nothing else was written, write a 0.
174 exp_buffer
[EXP_LEN
- 1] = '0';
175 exp_cur
= EXP_LEN
- 1;
178 exp_buffer
[exp_cur
- 1] = exp_is_negative
? '-' : '+';
181 // these are signed to prevent underflow due to negative values. The eventual
182 // values will always be non-negative.
183 size_t trailing_zeroes
= 0;
186 // prefix is "0x", and always appears.
187 constexpr size_t PREFIX_LEN
= 2;
188 char prefix
[PREFIX_LEN
];
190 prefix
[1] = a
+ ('x' - 'a');
191 const cpp::string_view
prefix_str(prefix
, PREFIX_LEN
);
193 // If the precision is greater than the actual result, pad with 0s
194 if (to_conv
.precision
> static_cast<int>(mant_digits
- 1))
195 trailing_zeroes
= to_conv
.precision
- (mant_digits
- 1);
197 bool has_hexadecimal_point
=
198 (mant_digits
> 1) || ((to_conv
.flags
& FormatFlags::ALTERNATE_FORM
) ==
199 FormatFlags::ALTERNATE_FORM
);
200 constexpr cpp::string_view
HEXADECIMAL_POINT(".");
202 // This is for the letter 'p' before the exponent.
203 const char exp_separator
= a
+ ('p' - 'a');
204 constexpr int EXP_SEPARATOR_LEN
= 1;
206 padding
= static_cast<int>(to_conv
.min_width
- (sign_char
> 0 ? 1 : 0) -
207 PREFIX_LEN
- mant_digits
- trailing_zeroes
-
208 static_cast<int>(has_hexadecimal_point
) -
209 EXP_SEPARATOR_LEN
- (EXP_LEN
- exp_cur
));
213 if ((to_conv
.flags
& FormatFlags::LEFT_JUSTIFIED
) ==
214 FormatFlags::LEFT_JUSTIFIED
) {
215 // The pattern is (sign), 0x, digit, (.), (other digits), (zeroes), p,
216 // exponent, (spaces)
218 RET_IF_RESULT_NEGATIVE(writer
->write(sign_char
));
219 RET_IF_RESULT_NEGATIVE(writer
->write(prefix_str
));
220 RET_IF_RESULT_NEGATIVE(writer
->write(mant_buffer
[0]));
221 if (has_hexadecimal_point
)
222 RET_IF_RESULT_NEGATIVE(writer
->write(HEXADECIMAL_POINT
));
224 RET_IF_RESULT_NEGATIVE(writer
->write({mant_buffer
+ 1, mant_digits
- 1}));
225 if (trailing_zeroes
> 0)
226 RET_IF_RESULT_NEGATIVE(writer
->write('0', trailing_zeroes
));
227 RET_IF_RESULT_NEGATIVE(writer
->write(exp_separator
));
228 RET_IF_RESULT_NEGATIVE(
229 writer
->write({exp_buffer
+ exp_cur
, EXP_LEN
- exp_cur
}));
231 RET_IF_RESULT_NEGATIVE(writer
->write(' ', padding
));
233 // The pattern is (spaces), (sign), 0x, (zeroes), digit, (.), (other
234 // digits), (zeroes), p, exponent
235 if ((padding
> 0) && ((to_conv
.flags
& FormatFlags::LEADING_ZEROES
) !=
236 FormatFlags::LEADING_ZEROES
))
237 RET_IF_RESULT_NEGATIVE(writer
->write(' ', padding
));
239 RET_IF_RESULT_NEGATIVE(writer
->write(sign_char
));
240 RET_IF_RESULT_NEGATIVE(writer
->write(prefix_str
));
241 if ((padding
> 0) && ((to_conv
.flags
& FormatFlags::LEADING_ZEROES
) ==
242 FormatFlags::LEADING_ZEROES
))
243 RET_IF_RESULT_NEGATIVE(writer
->write('0', padding
));
244 RET_IF_RESULT_NEGATIVE(writer
->write(mant_buffer
[0]));
245 if (has_hexadecimal_point
)
246 RET_IF_RESULT_NEGATIVE(writer
->write(HEXADECIMAL_POINT
));
248 RET_IF_RESULT_NEGATIVE(writer
->write({mant_buffer
+ 1, mant_digits
- 1}));
249 if (trailing_zeroes
> 0)
250 RET_IF_RESULT_NEGATIVE(writer
->write('0', trailing_zeroes
));
251 RET_IF_RESULT_NEGATIVE(writer
->write(exp_separator
));
252 RET_IF_RESULT_NEGATIVE(
253 writer
->write({exp_buffer
+ exp_cur
, EXP_LEN
- exp_cur
}));
258 } // namespace printf_core
259 } // namespace LIBC_NAMESPACE_DECL
261 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H