[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / libc / src / stdio / printf_core / int_converter.h
blob13fcf3f1aa2edac14b81d3f720e992a6bcc6de93
1 //===-- Integer Converter for printf ----------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H
12 #include "src/__support/CPP/span.h"
13 #include "src/__support/CPP/string_view.h"
14 #include "src/__support/common.h"
15 #include "src/__support/integer_to_string.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/writer.h"
20 #include <inttypes.h>
21 #include <stddef.h>
23 namespace LIBC_NAMESPACE {
24 namespace printf_core {
26 // These functions only work on characters that are already known to be in the
27 // alphabet. Their behavior is undefined otherwise.
28 LIBC_INLINE constexpr char to_lower(char a) { return a | 32; }
29 LIBC_INLINE constexpr bool is_lower(char a) { return (a & 32) > 0; }
31 namespace details {
33 using HexFmt = IntegerToString<uintmax_t, radix::Hex>;
34 using HexFmtUppercase = IntegerToString<uintmax_t, radix::Hex::Uppercase>;
35 using OctFmt = IntegerToString<uintmax_t, radix::Oct>;
36 using DecFmt = IntegerToString<uintmax_t>;
38 LIBC_INLINE constexpr size_t num_buf_size() {
39 constexpr auto max = [](size_t a, size_t b) -> size_t {
40 return (a < b) ? b : a;
42 return max(HexFmt::buffer_size(),
43 max(HexFmtUppercase::buffer_size(),
44 max(OctFmt::buffer_size(), DecFmt::buffer_size())));
47 LIBC_INLINE cpp::optional<cpp::string_view>
48 num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
49 if (to_lower(conv_name) == 'x') {
50 if (is_lower(conv_name))
51 return HexFmt::format_to(bufref, num);
52 else
53 return HexFmtUppercase::format_to(bufref, num);
54 } else if (conv_name == 'o') {
55 return OctFmt::format_to(bufref, num);
56 } else {
57 return DecFmt::format_to(bufref, num);
61 } // namespace details
63 LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
64 static constexpr size_t BITS_IN_BYTE = 8;
65 static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE;
67 uintmax_t num = static_cast<uintmax_t>(to_conv.conv_val_raw);
68 bool is_negative = false;
69 FormatFlags flags = to_conv.flags;
71 const char a = is_lower(to_conv.conv_name) ? 'a' : 'A';
73 // If the conversion is signed, then handle negative values.
74 if (to_conv.conv_name == 'd' || to_conv.conv_name == 'i') {
75 // Check if the number is negative by checking the high bit. This works even
76 // for smaller numbers because they're sign extended by default.
77 if ((num & (uintmax_t(1) << (BITS_IN_NUM - 1))) > 0) {
78 is_negative = true;
79 num = -num;
81 } else {
82 // These flags are only for signed conversions, so this removes them if the
83 // conversion is unsigned.
84 flags = FormatFlags(flags &
85 ~(FormatFlags::FORCE_SIGN | FormatFlags::SPACE_PREFIX));
88 num = apply_length_modifier(num, to_conv.length_modifier);
90 cpp::array<char, details::num_buf_size()> buf;
91 auto str = details::num_to_strview(num, buf, to_conv.conv_name);
92 if (!str)
93 return INT_CONVERSION_ERROR;
95 size_t digits_written = str->size();
97 char sign_char = 0;
99 if (is_negative)
100 sign_char = '-';
101 else if ((flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN)
102 sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX
103 else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX)
104 sign_char = ' ';
106 // These are signed to prevent underflow due to negative values. The eventual
107 // values will always be non-negative.
108 int zeroes;
109 int spaces;
111 // prefix is "0x" for hexadecimal, or the sign character for signed
112 // conversions. Since hexadecimal is unsigned these will never conflict.
113 size_t prefix_len;
114 char prefix[2];
115 if ((to_lower(to_conv.conv_name) == 'x') &&
116 ((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
117 prefix_len = 2;
118 prefix[0] = '0';
119 prefix[1] = a + ('x' - 'a');
120 } else {
121 prefix_len = (sign_char == 0 ? 0 : 1);
122 prefix[0] = sign_char;
125 // Negative precision indicates that it was not specified.
126 if (to_conv.precision < 0) {
127 if ((flags & (FormatFlags::LEADING_ZEROES | FormatFlags::LEFT_JUSTIFIED)) ==
128 FormatFlags::LEADING_ZEROES) {
129 // If this conv has flag 0 but not - and no specified precision, it's
130 // padded with 0's instead of spaces identically to if precision =
131 // min_width - (1 if sign_char). For example: ("%+04d", 1) -> "+001"
132 zeroes =
133 static_cast<int>(to_conv.min_width - digits_written - prefix_len);
134 spaces = 0;
135 } else {
136 // If there are enough digits to pass over the precision, just write the
137 // number, padded by spaces.
138 zeroes = 0;
139 spaces =
140 static_cast<int>(to_conv.min_width - digits_written - prefix_len);
142 } else {
143 // If precision was specified, possibly write zeroes, and possibly write
144 // spaces. Example: ("%5.4d", 10000) -> "10000"
145 // If the check for if zeroes is negative was not there, spaces would be
146 // incorrectly evaluated as 1.
148 // The standard treats the case when num and precision are both zeroes as
149 // special - it requires that no characters are produced. So, we adjust for
150 // that special case first.
151 if (num == 0 && to_conv.precision == 0)
152 digits_written = 0;
153 zeroes = static_cast<int>(to_conv.precision -
154 digits_written); // a negative value means 0
155 if (zeroes < 0)
156 zeroes = 0;
157 spaces = static_cast<int>(to_conv.min_width - zeroes - digits_written -
158 prefix_len);
161 // The standard says that alternate form for the o conversion "increases
162 // the precision, if and only if necessary, to force the first digit of the
163 // result to be a zero (if the value and precision are both 0, a single 0 is
164 // printed)"
165 // This if checks the following conditions:
166 // 1) is this an o conversion in alternate form?
167 // 2) does this number has a leading zero?
168 // 2a) ... because there are additional leading zeroes?
169 // 2b) ... because it is just "0", unless it will not write any digits.
170 const bool has_leading_zero =
171 (zeroes > 0) || ((num == 0) && (digits_written != 0));
172 if ((to_conv.conv_name == 'o') &&
173 ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) &&
174 !has_leading_zero) {
175 zeroes = 1;
176 --spaces;
179 if ((flags & FormatFlags::LEFT_JUSTIFIED) == FormatFlags::LEFT_JUSTIFIED) {
180 // If left justified it goes prefix zeroes digits spaces
181 if (prefix_len != 0)
182 RET_IF_RESULT_NEGATIVE(writer->write({prefix, prefix_len}));
183 if (zeroes > 0)
184 RET_IF_RESULT_NEGATIVE(writer->write('0', zeroes));
185 if (digits_written > 0)
186 RET_IF_RESULT_NEGATIVE(writer->write(*str));
187 if (spaces > 0)
188 RET_IF_RESULT_NEGATIVE(writer->write(' ', spaces));
189 } else {
190 // Else it goes spaces prefix zeroes digits
191 if (spaces > 0)
192 RET_IF_RESULT_NEGATIVE(writer->write(' ', spaces));
193 if (prefix_len != 0)
194 RET_IF_RESULT_NEGATIVE(writer->write({prefix, prefix_len}));
195 if (zeroes > 0)
196 RET_IF_RESULT_NEGATIVE(writer->write('0', zeroes));
197 if (digits_written > 0)
198 RET_IF_RESULT_NEGATIVE(writer->write(*str));
200 return WRITE_OK;
203 } // namespace printf_core
204 } // namespace LIBC_NAMESPACE
206 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_INT_CONVERTER_H