diff --git a/AK/Format.cpp b/AK/Format.cpp index 79333aa907..aaa556d00e 100644 --- a/AK/Format.cpp +++ b/AK/Format.cpp @@ -128,7 +128,7 @@ public: return false; if (!consume_number(index)) - return use_next_index; + index = use_next_index; if (!consume_specific('}')) ASSERT_NOT_REACHED(); @@ -146,7 +146,7 @@ void write_escaped_literal(StringBuilder& builder, StringView literal) } } -void vformat_impl(StringBuilder& builder, FormatStringParser& parser, Span parameters, size_t argument_index = 0) +void vformat_impl(StringBuilder& builder, FormatStringParser& parser, AK::FormatterContext& context) { const auto literal = parser.consume_literal(); write_escaped_literal(builder, literal); @@ -158,23 +158,25 @@ void vformat_impl(StringBuilder& builder, FormatStringParser& parser, Span parameters) +size_t decode_value(size_t value, AK::FormatterContext& context) { if (value == AK::StandardFormatter::value_from_next_arg) - TODO(); + value = AK::StandardFormatter::value_from_arg + context.take_next_index(); if (value >= AK::StandardFormatter::value_from_arg) { - const auto parameter = parameters.at(value - AK::StandardFormatter::value_from_arg); + const auto parameter = context.parameter_at(value - AK::StandardFormatter::value_from_arg); Optional svalue; if (parameter.type == AK::TypeErasedParameter::Type::UInt8) @@ -212,19 +214,21 @@ namespace AK { void vformat(StringBuilder& builder, StringView fmtstr, Span parameters) { FormatStringParser parser { fmtstr }; - vformat_impl(builder, parser, parameters); + FormatterContext context { parameters }; + vformat_impl(builder, parser, context); } void vformat(const LogStream& stream, StringView fmtstr, Span parameters) { StringBuilder builder; FormatStringParser parser { fmtstr }; - vformat_impl(builder, parser, parameters); + FormatterContext context { parameters }; + vformat_impl(builder, parser, context); stream << builder.to_string(); } -void StandardFormatter::parse(StringView flags) +void StandardFormatter::parse(FormatterContext& context) { - FormatStringParser parser { flags }; + FormatStringParser parser { context.flags() }; if (StringView { "<^>" }.contains(parser.peek(1))) { ASSERT(!parser.next_is(is_any_of("{}"))); @@ -253,7 +257,7 @@ void StandardFormatter::parse(StringView flags) if (size_t index = 0; parser.consume_replacement_field(index)) { if (index == use_next_index) - TODO(); + index = context.take_next_index(); m_width = value_from_arg + index; } else if (size_t width = 0; parser.consume_number(width)) { @@ -263,7 +267,7 @@ void StandardFormatter::parse(StringView flags) if (parser.consume_specific('.')) { if (size_t index = 0; parser.consume_replacement_field(index)) { if (index == use_next_index) - TODO(); + index = context.take_next_index(); m_precision = value_from_arg + index; } else if (size_t precision = 0; parser.consume_number(precision)) { @@ -296,7 +300,7 @@ void StandardFormatter::parse(StringView flags) ASSERT(parser.is_eof()); } -void Formatter::format(StringBuilder& builder, StringView value, Span) +void Formatter::format(StringBuilder& builder, StringView value, FormatterContext&) { if (m_align != Align::Default) TODO(); @@ -317,7 +321,7 @@ void Formatter::format(StringBuilder& builder, StringView value, Spa } template -void Formatter::value>::Type>::format(StringBuilder& builder, T value, Span parameters) +void Formatter::value>::Type>::format(StringBuilder& builder, T value, FormatterContext& context) { if (m_precision != value_not_set) ASSERT_NOT_REACHED(); @@ -344,7 +348,7 @@ void Formatter::value>::Type>::format(StringB ASSERT_NOT_REACHED(); } - auto width = decode_value(m_width, parameters); + auto width = decode_value(m_width, context); PrintfImplementation::Align align; if (m_align == Align::Left) diff --git a/AK/Format.h b/AK/Format.h index ab99e13b33..78f2d4f10c 100644 --- a/AK/Format.h +++ b/AK/Format.h @@ -76,7 +76,28 @@ struct TypeErasedParameter { const void* value; Type type; - void (*formatter)(StringBuilder& builder, const void* value, StringView flags, Span parameters); + void (*formatter)(StringBuilder& builder, const void* value, class FormatterContext&); +}; + +class FormatterContext { +public: + FormatterContext(Span parameters) + : m_parameters(parameters) + { + } + + const TypeErasedParameter& parameter_at(size_t index) const { return m_parameters.at(index); } + size_t parameter_count() const { return m_parameters.size(); } + + StringView flags() const { return m_flags; } + void set_flags(StringView value) { m_flags = value; } + + size_t take_next_index() { return m_next_index++; } + +private: + Span m_parameters; + StringView m_flags; + size_t m_next_index { 0 }; }; } // namespace AK @@ -84,12 +105,12 @@ struct TypeErasedParameter { namespace AK::Detail::Format { template -void format_value(StringBuilder& builder, const void* value, StringView flags, AK::Span parameters) +void format_value(StringBuilder& builder, const void* value, FormatterContext& context) { Formatter formatter; - formatter.parse(flags); - formatter.format(builder, *static_cast(value), parameters); + formatter.parse(context); + formatter.format(builder, *static_cast(value), context); } } // namespace AK::Detail::Format @@ -140,12 +161,12 @@ struct StandardFormatter { size_t m_width = value_not_set; size_t m_precision = value_not_set; - void parse(StringView flags); + void parse(FormatterContext&); }; template<> struct Formatter : StandardFormatter { - void format(StringBuilder& builder, StringView value, Span); + void format(StringBuilder& builder, StringView value, FormatterContext&); }; template<> struct Formatter : Formatter { @@ -162,7 +183,7 @@ struct Formatter : Formatter { template struct Formatter::value>::Type> : StandardFormatter { - void format(StringBuilder&, T value, Span); + void format(StringBuilder&, T value, FormatterContext&); }; template diff --git a/AK/Tests/TestFormat.cpp b/AK/Tests/TestFormat.cpp index 86227f8e16..898fd49df0 100644 --- a/AK/Tests/TestFormat.cpp +++ b/AK/Tests/TestFormat.cpp @@ -119,6 +119,7 @@ TEST_CASE(replacement_field) EXPECT_EQ(String::formatted("{:*<{1}}", 7, 4), "7***"); EXPECT_EQ(String::formatted("{:{2}}", -5, 8, 16), " -5"); EXPECT_EQ(String::formatted("{{{:*^{1}}}}", 1, 3), "{*1*}"); + EXPECT_EQ(String::formatted("{:0{}}", 1, 3), "001"); } TEST_MAIN(Format)