[libc-commits] [libc] e28ca2d - [libc] Support C23 'b' (binary) modifier in printf (#80851)
via libc-commits
libc-commits at lists.llvm.org
Wed Feb 7 10:26:43 PST 2024
Author: Artem Tyurin
Date: 2024-02-07T10:26:38-08:00
New Revision: e28ca2dd46c137fd33dd327aed1afb1e66a32908
URL: https://github.com/llvm/llvm-project/commit/e28ca2dd46c137fd33dd327aed1afb1e66a32908
DIFF: https://github.com/llvm/llvm-project/commit/e28ca2dd46c137fd33dd327aed1afb1e66a32908.diff
LOG: [libc] Support C23 'b' (binary) modifier in printf (#80851)
Reference: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2612.pdf.
Fixes https://github.com/llvm/llvm-project/issues/80727.
Added:
Modified:
libc/src/stdio/printf_core/converter.cpp
libc/src/stdio/printf_core/int_converter.h
libc/src/stdio/printf_core/parser.h
libc/test/src/stdio/printf_core/converter_test.cpp
libc/test/src/stdio/sprintf_test.cpp
Removed:
################################################################################
diff --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp
index 74a36cbf7432fb..52412aef3c5c15 100644
--- a/libc/src/stdio/printf_core/converter.cpp
+++ b/libc/src/stdio/printf_core/converter.cpp
@@ -58,6 +58,8 @@ int convert(Writer *writer, const FormatSection &to_conv) {
case 'o':
case 'x':
case 'X':
+ case 'b':
+ case 'B':
return convert_int(writer, to_conv);
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
case 'f':
diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h
index 7744d801cbc189..2efbf53d409382 100644
--- a/libc/src/stdio/printf_core/int_converter.h
+++ b/libc/src/stdio/printf_core/int_converter.h
@@ -33,14 +33,17 @@ using HexFmt = IntegerToString<uintmax_t, radix::Hex>;
using HexFmtUppercase = IntegerToString<uintmax_t, radix::Hex::Uppercase>;
using OctFmt = IntegerToString<uintmax_t, radix::Oct>;
using DecFmt = IntegerToString<uintmax_t>;
+using BinFmt = IntegerToString<uintmax_t, radix::Bin>;
LIBC_INLINE constexpr size_t num_buf_size() {
- constexpr auto max = [](size_t a, size_t b) -> size_t {
- return (a < b) ? b : a;
- };
- return max(HexFmt::buffer_size(),
- max(HexFmtUppercase::buffer_size(),
- max(OctFmt::buffer_size(), DecFmt::buffer_size())));
+ cpp::array<size_t, 5> sizes{
+ HexFmt::buffer_size(), HexFmtUppercase::buffer_size(),
+ OctFmt::buffer_size(), DecFmt::buffer_size(), BinFmt::buffer_size()};
+
+ auto result = sizes[0];
+ for (size_t i = 1; i < sizes.size(); i++)
+ result = cpp::max(result, sizes[i]);
+ return result;
}
LIBC_INLINE cpp::optional<cpp::string_view>
@@ -52,6 +55,8 @@ num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
return HexFmtUppercase::format_to(bufref, num);
} else if (conv_name == 'o') {
return OctFmt::format_to(bufref, num);
+ } else if (to_lower(conv_name) == 'b') {
+ return BinFmt::format_to(bufref, num);
} else {
return DecFmt::format_to(bufref, num);
}
@@ -116,6 +121,11 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
prefix_len = 2;
prefix[0] = '0';
prefix[1] = a + ('x' - 'a');
+ } else if ((to_lower(to_conv.conv_name) == 'b') &&
+ ((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
+ prefix_len = 2;
+ prefix[0] = '0';
+ prefix[1] = a + ('b' - 'a');
} else {
prefix_len = (sign_char == 0 ? 0 : 1);
prefix[0] = sign_char;
diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h
index ab491655275fb9..1e7d2e58c924a6 100644
--- a/libc/src/stdio/printf_core/parser.h
+++ b/libc/src/stdio/printf_core/parser.h
@@ -159,6 +159,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
+ case ('b'):
+ case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
@@ -484,6 +486,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
+ case ('b'):
+ case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp
index 8404ef6ec7db4d..9da749f3b8ad1a 100644
--- a/libc/test/src/stdio/printf_core/converter_test.cpp
+++ b/libc/test/src/stdio/printf_core/converter_test.cpp
@@ -210,6 +210,20 @@ TEST_F(LlvmLibcPrintfConverterTest, HexConversion) {
ASSERT_EQ(writer.get_chars_written(), 18);
}
+TEST_F(LlvmLibcPrintfConverterTest, BinaryConversion) {
+ LIBC_NAMESPACE::printf_core::FormatSection section;
+ section.has_conv = true;
+ section.raw_string = "%b";
+ section.conv_name = 'b';
+ section.conv_val_raw = 42;
+ LIBC_NAMESPACE::printf_core::convert(&writer, section);
+
+ wb.buff[wb.buff_cur] = '\0';
+
+ ASSERT_STREQ(str, "101010");
+ ASSERT_EQ(writer.get_chars_written(), 6);
+}
+
TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) {
LIBC_NAMESPACE::printf_core::FormatSection section;
diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index f3614b05a0c3e6..186b37e2898af6 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -410,6 +410,119 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
ASSERT_STREQ(buff, "007F 0x1000000000 002 ");
}
+TEST(LlvmLibcSPrintfTest, BinConv) {
+ char buff[64];
+ int written;
+
+ // Basic Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%b", 42);
+ EXPECT_EQ(written, 6);
+ ASSERT_STREQ(buff, "101010");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%B", 12081991);
+ EXPECT_EQ(written, 24);
+ ASSERT_STREQ(buff, "101110000101101101000111");
+
+ // Min Width Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%10b", 0b101010);
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, " 101010");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%2B", 0b101010);
+ EXPECT_EQ(written, 6);
+ ASSERT_STREQ(buff, "101010");
+
+ // Precision Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%b", 0);
+ EXPECT_EQ(written, 1);
+ ASSERT_STREQ(buff, "0");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%.0b", 0);
+ EXPECT_EQ(written, 0);
+ ASSERT_STREQ(buff, "");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%.5b", 0b111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, "00111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%.2b", 0b111);
+ EXPECT_EQ(written, 3);
+ ASSERT_STREQ(buff, "111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%3b", 0b111);
+ EXPECT_EQ(written, 3);
+ ASSERT_STREQ(buff, "111");
+
+ // Flag Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%-5b", 0b111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, "111 ");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#b", 0b111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, "0b111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#b", 0);
+ EXPECT_EQ(written, 1);
+ ASSERT_STREQ(buff, "0");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#B", 0b111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, "0B111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%05b", 0b111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, "00111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%0#6b", 0b111);
+ EXPECT_EQ(written, 6);
+ ASSERT_STREQ(buff, "0b0111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%-#6b", 0b111);
+ EXPECT_EQ(written, 6);
+ ASSERT_STREQ(buff, "0b111 ");
+
+ // Combined Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#-07b", 0b111);
+ EXPECT_EQ(written, 7);
+ ASSERT_STREQ(buff, "0b111 ");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%7.5b", 0b111);
+ EXPECT_EQ(written, 7);
+ ASSERT_STREQ(buff, " 00111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#9.5B", 0b111);
+ EXPECT_EQ(written, 9);
+ ASSERT_STREQ(buff, " 0B00111");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%#.b", 0);
+ EXPECT_EQ(written, 0);
+ ASSERT_STREQ(buff, "");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%-7.5b", 0b111);
+ EXPECT_EQ(written, 7);
+ ASSERT_STREQ(buff, "00111 ");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%5.4b", 0b1111);
+ EXPECT_EQ(written, 5);
+ ASSERT_STREQ(buff, " 1111");
+
+ // Multiple Conversion Tests.
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%10B %-#10b", 0b101, 0b110);
+ EXPECT_EQ(written, 21);
+ ASSERT_STREQ(buff, " 101 0b110 ");
+
+ written = LIBC_NAMESPACE::sprintf(buff, "%-5.4b%#.4b", 0b101, 0b110);
+ EXPECT_EQ(written, 11);
+ ASSERT_STREQ(buff, "0101 0b0110");
+}
+
TEST(LlvmLibcSPrintfTest, PointerConv) {
char buff[64];
int written;
More information about the libc-commits
mailing list