From 01915a30272a108ad244af6ec7fe5644674540b4 Mon Sep 17 00:00:00 2001 From: asynts Date: Sat, 26 Sep 2020 15:26:14 +0200 Subject: [PATCH] AK+Format: Use the new format backend in the implementation. --- AK/Format.cpp | 70 +++++++++++++++++++++++++++-------------- AK/Format.h | 2 ++ AK/Tests/TestFormat.cpp | 35 ++++++++++++++++++++- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/AK/Format.cpp b/AK/Format.cpp index 7052fcadb64..f273e207aa1 100644 --- a/AK/Format.cpp +++ b/AK/Format.cpp @@ -209,12 +209,16 @@ void StandardFormatter::parse(StringView specifier) if (lexer.consume_specific('b')) m_mode = Mode::Binary; + else if (lexer.consume_specific('B')) + m_mode = Mode::BinaryUppercase; else if (lexer.consume_specific('d')) m_mode = Mode::Decimal; else if (lexer.consume_specific('o')) m_mode = Mode::Octal; else if (lexer.consume_specific('x')) m_mode = Mode::Hexadecimal; + else if (lexer.consume_specific('X')) + m_mode = Mode::HexadecimalUppercase; else if (lexer.consume_specific('c')) m_mode = Mode::Character; else if (lexer.consume_specific('s')) @@ -251,28 +255,30 @@ void Formatter::format(StringBuilder& builder, StringView value, Spa template void Formatter::value>::Type>::format(StringBuilder& builder, T value, Span parameters) { - if (m_align != Align::Default) - TODO(); - if (m_sign != Sign::Default) - TODO(); - if (m_alternative_form) - TODO(); if (m_precision != value_not_set) ASSERT_NOT_REACHED(); if (m_mode == Mode::Character) TODO(); - int base; - if (m_mode == Mode::Binary) - TODO(); - else if (m_mode == Mode::Octal) - TODO(); - else if (m_mode == Mode::Decimal || m_mode == Mode::Default) + u8 base; + bool upper_case = false; + if (m_mode == Mode::Binary) { + base = 2; + } else if (m_mode == Mode::BinaryUppercase) { + base = 2; + upper_case = true; + } else if (m_mode == Mode::Octal) { + base = 8; + } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) { base = 10; - else if (m_mode == Mode::Hexadecimal) + } else if (m_mode == Mode::Hexadecimal) { base = 16; - else + } else if (m_mode == Mode::HexadecimalUppercase) { + base = 16; + upper_case = true; + } else { ASSERT_NOT_REACHED(); + } size_t width = m_width; if (m_width >= value_from_arg) { @@ -283,16 +289,34 @@ void Formatter::value>::Type>::format(StringB width = *reinterpret_cast(parameter.value); } - // FIXME: We really need one canonical print implementation that just takes a base. - (void)base; - - char* bufptr; - if (m_mode == Mode::Hexadecimal) - PrintfImplementation::print_hex([&](auto, char ch) { builder.append(ch); }, bufptr, value, false, false, false, m_zero_pad, width); - else if (IsSame::Type, T>::value) - PrintfImplementation::print_u64([&](auto, char ch) { builder.append(ch); }, bufptr, value, false, m_zero_pad, width); + PrintfImplementation::Align align; + if (m_align == Align::Left) + align = PrintfImplementation::Align::Left; + else if (m_align == Align::Right) + align = PrintfImplementation::Align::Right; + else if (m_align == Align::Center) + align = PrintfImplementation::Align::Center; + else if (m_align == Align::Default) + align = PrintfImplementation::Align::Right; else - PrintfImplementation::print_i64([&](auto, char ch) { builder.append(ch); }, bufptr, value, false, m_zero_pad, width); + ASSERT_NOT_REACHED(); + + PrintfImplementation::SignMode sign_mode; + if (m_sign == Sign::Default) + sign_mode = PrintfImplementation::SignMode::OnlyIfNeeded; + else if (m_sign == Sign::NegativeOnly) + sign_mode = PrintfImplementation::SignMode::OnlyIfNeeded; + else if (m_sign == Sign::PositiveAndNegative) + sign_mode = PrintfImplementation::SignMode::Always; + else if (m_sign == Sign::ReserveSpace) + sign_mode = PrintfImplementation::SignMode::Reserved; + else + ASSERT_NOT_REACHED(); + + if (IsSame::Type, T>::value) + PrintfImplementation::convert_unsigned_to_string(value, builder, base, m_alternative_form, upper_case, m_zero_pad, align, width, m_fill, sign_mode); + else + PrintfImplementation::convert_signed_to_string(value, builder, base, m_alternative_form, upper_case, m_zero_pad, align, width, m_fill, sign_mode); } template struct Formatter; diff --git a/AK/Format.h b/AK/Format.h index 1ab74b599d0..1922f548f99 100644 --- a/AK/Format.h +++ b/AK/Format.h @@ -81,9 +81,11 @@ struct StandardFormatter { enum class Mode { Default, Binary, + BinaryUppercase, Decimal, Octal, Hexadecimal, + HexadecimalUppercase, Character, String, Pointer, diff --git a/AK/Tests/TestFormat.cpp b/AK/Tests/TestFormat.cpp index a58e82850a2..da927de596d 100644 --- a/AK/Tests/TestFormat.cpp +++ b/AK/Tests/TestFormat.cpp @@ -40,11 +40,12 @@ TEST_CASE(format_integers) EXPECT_EQ(String::formatted("{}", 42u), "42"); EXPECT_EQ(String::formatted("{:4}", 42u), " 42"); EXPECT_EQ(String::formatted("{:08}", 42u), "00000042"); - // EXPECT_EQ(String::formatted("{:7}", -17), " -17"); + EXPECT_EQ(String::formatted("{:7}", -17), " -17"); EXPECT_EQ(String::formatted("{}", -17), "-17"); EXPECT_EQ(String::formatted("{:04}", 13), "0013"); EXPECT_EQ(String::formatted("{:08x}", 4096), "00001000"); EXPECT_EQ(String::formatted("{:x}", 0x1111222233334444ull), "1111222233334444"); + EXPECT_EQ(String::formatted("{:4}", 12345678), "12345678"); } TEST_CASE(reorder_format_arguments) @@ -80,4 +81,36 @@ TEST_CASE(format_without_arguments) EXPECT_EQ(String::formatted("foo"), "foo"); } +TEST_CASE(format_upper_case_integer) +{ + EXPECT_EQ(String::formatted("{:4X}", 0xff), " FF"); + EXPECT_EQ(String::formatted("{:#4X}", 0xff), "0XFF"); + + EXPECT_EQ(String::formatted("{:b}", 0xff), "11111111"); + EXPECT_EQ(String::formatted("{:B}", 0xff), "11111111"); + EXPECT_EQ(String::formatted("{:#b}", 0xff), "0b11111111"); +} + +TEST_CASE(format_aligned) +{ + EXPECT_EQ(String::formatted("{:*<8}", 13), "13******"); + EXPECT_EQ(String::formatted("{:*^8}", 13), "***13***"); + EXPECT_EQ(String::formatted("{:*>8}", 13), "******13"); + EXPECT_EQ(String::formatted("{:*>+8}", 13), "*****+13"); + EXPECT_EQ(String::formatted("{:*^ 8}", 13), "** 13***"); +} + +TEST_CASE(format_octal) +{ + EXPECT_EQ(String::formatted("{:o}", 0744), "744"); + EXPECT_EQ(String::formatted("{:#o}", 0744), "0744"); +} + +TEST_CASE(zero_pad) +{ + EXPECT_EQ(String::formatted("{: <010}", 42), "42 "); + EXPECT_EQ(String::formatted("{:010}", 42), "0000000042"); + EXPECT_EQ(String::formatted("{:/^010}", 42), "////42////"); +} + TEST_MAIN(Format)