9
9
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
10
10
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
11
11
12
+ #include " src/__support/CPP/ArrayRef.h"
13
+ #include " src/__support/CPP/StringView.h"
12
14
#include " src/__support/integer_to_string.h"
13
15
#include " src/stdio/printf_core/converter_utils.h"
14
16
#include " src/stdio/printf_core/core_structs.h"
20
22
namespace __llvm_libc {
21
23
namespace printf_core {
22
24
25
+ // These functions only work on characters that are already known to be in the
26
+ // alphabet. Their behavior is undefined otherwise.
27
+ constexpr char inline to_lower (char a) { return a | 32 ; }
28
+ constexpr bool inline is_lower (char a) { return (a & 32 ) > 0 ; }
29
+
30
+ cpp::optional<cpp::StringView> inline num_to_strview (
31
+ uintmax_t num, cpp::MutableArrayRef<char > bufref, char conv_name) {
32
+ if (to_lower (conv_name) == ' x' ) {
33
+ return IntegerToString<uintmax_t , 16 >::convert (num, bufref,
34
+ is_lower (conv_name));
35
+ } else if (conv_name == ' o' ) {
36
+ return IntegerToString<uintmax_t , 8 >::convert (num, bufref, true );
37
+ } else {
38
+ return IntegerToString<uintmax_t , 10 >::convert (num, bufref, true );
39
+ }
40
+ }
41
+
23
42
int inline convert_int (Writer *writer, const FormatSection &to_conv) {
24
43
static constexpr size_t BITS_IN_BYTE = 8 ;
25
44
static constexpr size_t BITS_IN_NUM = sizeof (uintmax_t ) * BITS_IN_BYTE;
@@ -28,24 +47,33 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
28
47
bool is_negative = false ;
29
48
FormatFlags flags = to_conv.flags ;
30
49
31
- if (to_conv.conv_name == ' u' ) {
32
- // These flags are only for signed conversions, so this removes them if the
33
- // conversion is unsigned.
34
- flags = FormatFlags (flags &
35
- ~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX));
36
- } else {
50
+ const char a = is_lower (to_conv.conv_name ) ? ' a' : ' A' ;
51
+
52
+ // If the conversion is signed, then handle negative values.
53
+ if (to_conv.conv_name == ' d' || to_conv.conv_name == ' i' ) {
37
54
// Check if the number is negative by checking the high bit. This works even
38
55
// for smaller numbers because they're sign extended by default.
39
56
if ((num & (uintmax_t (1 ) << (BITS_IN_NUM - 1 ))) > 0 ) {
40
57
is_negative = true ;
41
58
num = -num;
42
59
}
60
+ } else {
61
+ // These flags are only for signed conversions, so this removes them if the
62
+ // conversion is unsigned.
63
+ flags = FormatFlags (flags &
64
+ ~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX));
43
65
}
44
66
45
67
num = apply_length_modifier (num, to_conv.length_modifier );
46
68
47
- auto const int_to_str = integer_to_string (num);
48
- size_t digits_written = int_to_str.str ().size ();
69
+ static constexpr size_t BUFSIZE = IntegerToString<uintmax_t , 8 >::BUFSIZE;
70
+ char buff[BUFSIZE];
71
+ cpp::MutableArrayRef<char > bufref (buff, BUFSIZE);
72
+ auto str = num_to_strview (num, bufref, to_conv.conv_name );
73
+ if (!str)
74
+ return INT_CONVERSION_ERROR;
75
+
76
+ size_t digits_written = str->size ();
49
77
50
78
char sign_char = 0 ;
51
79
@@ -56,29 +84,39 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
56
84
else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX)
57
85
sign_char = ' ' ;
58
86
59
- int sign_char_len = (sign_char == 0 ? 0 : 1 );
60
-
61
87
// These are signed to prevent underflow due to negative values. The eventual
62
88
// values will always be non-negative.
63
89
int zeroes;
64
90
int spaces;
65
91
92
+ // prefix is "0x" for hexadecimal, or the sign character for signed
93
+ // conversions. Since hexadecimal is unsigned these will never conflict.
94
+ int prefix_len;
95
+ char prefix[2 ];
96
+ if ((to_lower (to_conv.conv_name ) == ' x' ) &&
97
+ ((flags & FormatFlags::ALTERNATE_FORM) != 0 )) {
98
+ prefix_len = 2 ;
99
+ prefix[0 ] = ' 0' ;
100
+ prefix[1 ] = a + (' x' - ' a' );
101
+ } else {
102
+ prefix_len = (sign_char == 0 ? 0 : 1 );
103
+ prefix[0 ] = sign_char;
104
+ }
105
+
66
106
// Negative precision indicates that it was not specified.
67
107
if (to_conv.precision < 0 ) {
68
108
if ((flags & (FormatFlags::LEADING_ZEROES | FormatFlags::LEFT_JUSTIFIED)) ==
69
109
FormatFlags::LEADING_ZEROES) {
70
110
// If this conv has flag 0 but not - and no specified precision, it's
71
111
// padded with 0's instead of spaces identically to if precision =
72
112
// min_width - (1 if sign_char). For example: ("%+04d", 1) -> "+001"
73
- zeroes = to_conv.min_width - digits_written - sign_char_len;
74
- if (zeroes < 0 )
75
- zeroes = 0 ;
113
+ zeroes = to_conv.min_width - digits_written - prefix_len;
76
114
spaces = 0 ;
77
115
} else {
78
116
// If there are enough digits to pass over the precision, just write the
79
117
// number, padded by spaces.
80
118
zeroes = 0 ;
81
- spaces = to_conv.min_width - digits_written - sign_char_len ;
119
+ spaces = to_conv.min_width - digits_written - prefix_len ;
82
120
}
83
121
} else {
84
122
// If precision was specified, possibly write zeroes, and possibly write
@@ -94,33 +132,35 @@ int inline convert_int(Writer *writer, const FormatSection &to_conv) {
94
132
zeroes = to_conv.precision - digits_written; // a negative value means 0
95
133
if (zeroes < 0 )
96
134
zeroes = 0 ;
97
- spaces = to_conv.min_width - zeroes - digits_written - sign_char_len;
135
+ spaces = to_conv.min_width - zeroes - digits_written - prefix_len;
136
+ }
137
+
138
+ if ((to_conv.conv_name == ' o' ) &&
139
+ ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0 ) && zeroes < 1 ) {
140
+ zeroes = 1 ;
141
+ --spaces;
98
142
}
99
- if (spaces < 0 )
100
- spaces = 0 ;
101
143
102
144
if ((flags & FormatFlags::LEFT_JUSTIFIED) == FormatFlags::LEFT_JUSTIFIED) {
103
- // If left justified it goes sign zeroes digits spaces
104
- if (sign_char != 0 )
105
- RET_IF_RESULT_NEGATIVE (writer->write (&sign_char, 1 ));
145
+ // If left justified it goes prefix zeroes digits spaces
146
+ if (prefix_len != 0 )
147
+ RET_IF_RESULT_NEGATIVE (writer->write (prefix, prefix_len ));
106
148
if (zeroes > 0 )
107
149
RET_IF_RESULT_NEGATIVE (writer->write_chars (' 0' , zeroes));
108
150
if (digits_written > 0 )
109
- RET_IF_RESULT_NEGATIVE (
110
- writer->write (int_to_str.str ().data (), digits_written));
151
+ RET_IF_RESULT_NEGATIVE (writer->write (str->data (), digits_written));
111
152
if (spaces > 0 )
112
153
RET_IF_RESULT_NEGATIVE (writer->write_chars (' ' , spaces));
113
154
} else {
114
- // Else it goes spaces sign zeroes digits
155
+ // Else it goes spaces prefix zeroes digits
115
156
if (spaces > 0 )
116
157
RET_IF_RESULT_NEGATIVE (writer->write_chars (' ' , spaces));
117
- if (sign_char != 0 )
118
- RET_IF_RESULT_NEGATIVE (writer->write (&sign_char, 1 ));
158
+ if (prefix_len != 0 )
159
+ RET_IF_RESULT_NEGATIVE (writer->write (prefix, prefix_len ));
119
160
if (zeroes > 0 )
120
161
RET_IF_RESULT_NEGATIVE (writer->write_chars (' 0' , zeroes));
121
162
if (digits_written > 0 )
122
- RET_IF_RESULT_NEGATIVE (
123
- writer->write (int_to_str.str ().data (), digits_written));
163
+ RET_IF_RESULT_NEGATIVE (writer->write (str->data (), digits_written));
124
164
}
125
165
return WRITE_OK;
126
166
}
0 commit comments