AK: Add Utf16StringBuilder formatting helpers

Add vformat support for Utf16StringBuilder and expose appendff and
try_appendff helpers on the builder itself. This lets callers build a
Utf16String on the purpose-built UTF-16 path even when using formatting.

Use the new API for Utf16String::formatted and add AK coverage for
formatting directly into a Utf16StringBuilder.
This commit is contained in:
Andreas Kling 2026-06-22 02:30:26 +02:00 committed by Andreas Kling
parent 488006d276
commit bf5f24ab36
5 changed files with 40 additions and 2 deletions

View file

@ -17,6 +17,8 @@
#include <AK/StringBuilder.h>
#include <AK/StringConversions.h>
#include <AK/Time.h>
#include <AK/Utf16String.h>
#include <AK/Utf16StringBuilder.h>
#include <math.h>
#include <pthread.h>
#include <stdio.h>
@ -823,6 +825,14 @@ ErrorOr<void> vformat(StringBuilder& builder, StringView fmtstr, TypeErasedForma
return {};
}
ErrorOr<void> vformat(Utf16StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params)
{
StringBuilder string_builder(StringBuilder::Mode::UTF16);
TRY(vformat(string_builder, fmtstr, params));
builder.append(string_builder.to_utf16_string());
return {};
}
void StandardFormatter::parse(TypeErasedFormatParams& params, FormatParser& parser)
{
if ("<^>"sv.contains(parser.peek(1))) {

View file

@ -616,6 +616,7 @@ struct Formatter<Checked<T>> : Formatter<T> {
};
ErrorOr<void> vformat(StringBuilder&, StringView fmtstr, TypeErasedFormatParams&);
ErrorOr<void> vformat(Utf16StringBuilder&, StringView fmtstr, TypeErasedFormatParams&);
void vout(FILE*, StringView fmtstr, TypeErasedFormatParams&, bool newline = false);

View file

@ -16,6 +16,7 @@
#include <AK/Traits.h>
#include <AK/UnicodeUtils.h>
#include <AK/Utf16StringBase.h>
#include <AK/Utf16StringBuilder.h>
#include <AK/Utf16StringData.h>
#include <AK/Utf16View.h>
#include <AK/Utf8View.h>
@ -113,12 +114,12 @@ public:
template<typename... Parameters>
ALWAYS_INLINE static Utf16String formatted(CheckedFormatString<Parameters...>&& format, Parameters const&... parameters)
{
StringBuilder builder(StringBuilder::Mode::UTF16);
Utf16StringBuilder builder;
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_parameters { parameters... };
MUST(vformat(builder, format.view(), variadic_format_parameters));
return builder.to_utf16_string();
return builder.to_string();
}
template<Integral T>

View file

@ -7,6 +7,7 @@
#pragma once
#include <AK/Badge.h>
#include <AK/Format.h>
#include <AK/Forward.h>
#include <AK/Optional.h>
#include <AK/Span.h>
@ -85,6 +86,20 @@ public:
void append_repeated_ascii(char, size_t);
void append_repeated(Utf16View const&, size_t);
template<typename... Parameters>
ErrorOr<void> try_appendff(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
{
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_parameters { parameters... };
return vformat(*this, fmtstr.view(), variadic_format_parameters);
}
template<typename... Parameters>
void appendff(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
{
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_parameters { parameters... };
MUST(vformat(*this, fmtstr.view(), variadic_format_parameters));
}
[[nodiscard]] Utf16String to_string();
[[nodiscard]] Utf16View view() const;

View file

@ -108,3 +108,14 @@ TEST_CASE(reuse_after_creating_long_utf16_string)
EXPECT_EQ(builder.view(), "ok"sv);
EXPECT_EQ(builder.to_string(), "ok"sv);
}
TEST_CASE(formatted_append)
{
Utf16StringBuilder builder;
builder.appendff("{} {} {}", "hello"sv, Utf16View { u"\u263A"sv }, 42);
MUST(builder.try_appendff(" {}", Utf16String::formatted("{}", 3.14)));
auto string = builder.to_string();
EXPECT_EQ(string, u"hello \u263A 42 3.14"sv);
EXPECT(!string.is_ascii());
}