1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 08:27:46 +00:00

AK: Resolve format related circular dependencies properly.

With this commit, <AK/Format.h> has a more supportive role and isn't
used directly.

Essentially, there now is a public 'vformat' function ('v' for vector)
which takes already type erased parameters. The name is choosen to
indicate that this function behaves similar to C-style functions taking
a va_list equivalent.

The interface for frontend users are now 'String::formatted' and
'StringBuilder::appendff'.
This commit is contained in:
asynts 2020-09-23 13:21:18 +02:00 committed by Andreas Kling
parent 3224fb7d55
commit b7a4c4482f
8 changed files with 105 additions and 100 deletions

View file

@ -27,9 +27,12 @@
#pragma once
#include <AK/Array.h>
#include <AK/String.h>
#include <AK/StringView.h>
// FIXME: I would really love to merge the format_value and make_type_erased_parameters functions,
// but the compiler creates weird error messages when I do that. Here is a small snippet that
// reproduces the issue: https://godbolt.org/z/o55crs
namespace AK {
template<typename T, typename = void>
@ -51,36 +54,25 @@ bool format_value(StringBuilder& builder, const void* value, StringView flags)
return true;
}
struct TypeErasedFormatter {
bool (*format)(StringBuilder& builder, const void* value, StringView flags);
const void* parameter;
};
template<typename T>
TypeErasedFormatter make_type_erased_formatter(const T& value) { return { format_value<T>, &value }; }
String format(StringView fmtstr, AK::Span<TypeErasedFormatter>, size_t argument_index = 0);
void format(StringBuilder&, StringView fmtstr, AK::Span<TypeErasedFormatter>, size_t argument_index = 0);
} // namespace AK::Detail::Format
namespace AK {
template<size_t Size>
struct Formatter<char[Size]> {
bool parse(StringView) { return true; }
void format(StringBuilder& builder, const char* value) { builder.append(value); }
struct TypeErasedParameter {
const void* value;
bool (*formatter)(StringBuilder& builder, const void* value, StringView flags);
};
template<>
struct Formatter<StringView> {
bool parse(StringView flags) { return flags.is_empty(); }
void format(StringBuilder& builder, StringView value) { builder.append(value); }
bool parse(StringView flags);
void format(StringBuilder& builder, StringView value);
};
template<size_t Size>
struct Formatter<char[Size]> : Formatter<StringView> {
};
template<>
struct Formatter<String> {
bool parse(StringView flags) { return flags.is_empty(); }
void format(StringBuilder& builder, const String& value) { builder.append(value); }
struct Formatter<String> : Formatter<StringView> {
};
template<typename T>
@ -94,19 +86,11 @@ struct Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type> {
};
template<typename... Parameters>
String format(StringView fmtstr, const Parameters&... parameters)
Array<TypeErasedParameter, sizeof...(Parameters)> make_type_erased_parameters(const Parameters&... parameters)
{
Array<Detail::Format::TypeErasedFormatter, sizeof...(parameters)> formatters { Detail::Format::make_type_erased_formatter(parameters)... };
return Detail::Format::format(fmtstr, formatters);
}
template<typename... Parameters>
void format(StringBuilder& builder, StringView fmtstr, const Parameters&... parameters)
{
Array<Detail::Format::TypeErasedFormatter, sizeof...(parameters)> formatters { Detail::Format::make_type_erased_formatter(parameters)... };
Detail::Format::format(builder, fmtstr, formatters);
return { TypeErasedParameter { &parameters, Detail::Format::format_value<Parameters> }... };
}
template<typename... Parameters>
void StringBuilder::appendff(StringView fmtstr, const Parameters&... parameters) { AK::format(*this, fmtstr, parameters...); }
void vformat(StringBuilder& builder, StringView fmtstr, Span<const TypeErasedParameter>, size_t argument_index = 0);
} // namespace AK