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

AK+Format: Do some housekeeping in the format implementation.

This commit is contained in:
asynts 2020-10-02 15:21:30 +02:00 committed by Andreas Kling
parent ac5e08a541
commit 6351a56d27
13 changed files with 476 additions and 640 deletions

View file

@ -27,6 +27,7 @@
#pragma once
#include <AK/Array.h>
#include <AK/GenericLexer.h>
#include <AK/StringView.h>
// FIXME: I would really love to merge the format_value and make_type_erased_parameters functions,
@ -35,9 +36,15 @@
namespace AK {
class TypeErasedFormatParams;
class FormatParser;
class FormatBuilder;
template<typename T, typename = void>
struct Formatter;
constexpr size_t max_format_arguments = 256;
struct TypeErasedParameter {
enum class Type {
UInt8,
@ -76,65 +83,131 @@ struct TypeErasedParameter {
const void* value;
Type type;
void (*formatter)(StringBuilder& builder, const void* value, class FormatterContext&);
void (*formatter)(TypeErasedFormatParams&, FormatBuilder&, FormatParser&, const void* value);
};
class FormatterContext {
class FormatParser : public GenericLexer {
public:
FormatterContext(Span<const TypeErasedParameter> parameters)
struct FormatSpecifier {
StringView flags;
size_t index;
};
explicit FormatParser(StringView input);
StringView consume_literal();
bool consume_number(size_t& value);
bool consume_specifier(FormatSpecifier& specifier);
bool consume_replacement_field(size_t& index);
};
class FormatBuilder {
public:
enum class Align {
Default,
Left,
Center,
Right,
};
enum class SignMode {
OnlyIfNeeded,
Always,
Reserved,
Default = OnlyIfNeeded,
};
explicit FormatBuilder(StringBuilder& builder)
: m_builder(builder)
{
}
void put_padding(char fill, size_t amount);
void put_literal(StringView value);
void put_string(
StringView value,
Align align = Align::Left,
size_t min_width = 0,
size_t max_width = NumericLimits<size_t>::max(),
char fill = ' ');
void put_u64(
u64 value,
u8 base = 10,
bool prefix = false,
bool upper_case = false,
bool zero_pad = false,
Align align = Align::Right,
size_t min_width = 0,
char fill = ' ',
SignMode sign_mode = SignMode::OnlyIfNeeded,
bool is_negative = false);
void put_i64(
i64 value,
u8 base = 10,
bool prefix = false,
bool upper_case = false,
bool zero_pad = false,
Align align = Align::Right,
size_t min_width = 0,
char fill = ' ',
SignMode sign_mode = SignMode::OnlyIfNeeded);
const StringBuilder& builder() const { return m_builder; }
StringBuilder& builder() { return m_builder; }
private:
StringBuilder& m_builder;
};
class TypeErasedFormatParams {
public:
explicit TypeErasedFormatParams(Span<const TypeErasedParameter> 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; }
Span<const TypeErasedParameter> parameters() const { return m_parameters; }
size_t take_next_index() { return m_next_index++; }
size_t decode(size_t value, size_t default_value = 0);
private:
Span<const TypeErasedParameter> m_parameters;
StringView m_flags;
size_t m_next_index { 0 };
};
} // namespace AK
namespace AK::Detail::Format {
template<typename T>
void format_value(StringBuilder& builder, const void* value, FormatterContext& context)
void __format_value(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser, const void* value)
{
Formatter<T> formatter;
formatter.parse(context);
formatter.format(builder, *static_cast<const T*>(value), context);
formatter.parse(params, parser);
formatter.format(params, builder, *static_cast<const T*>(value));
}
} // namespace AK::Detail::Format
template<typename... Parameters>
class VariadicFormatParams : public TypeErasedFormatParams {
public:
static_assert(sizeof...(Parameters) <= max_format_arguments);
namespace AK {
explicit VariadicFormatParams(const Parameters&... parameters)
: TypeErasedFormatParams(m_data)
, m_data({ TypeErasedParameter { &parameters, TypeErasedParameter::get_type<Parameters>(), __format_value<Parameters> }... })
{
}
constexpr size_t max_format_arguments = 256;
private:
Array<TypeErasedParameter, sizeof...(Parameters)> m_data;
};
// We use the same format for most types for consistency. This is taken directly from std::format.
// Not all valid options do anything yet.
// https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
struct StandardFormatter {
enum class Align {
Default,
Left,
Right,
Center,
};
enum class Sign {
NegativeOnly,
PositiveAndNegative,
ReserveSpace,
Default = NegativeOnly
};
enum class Mode {
Default,
Binary,
@ -148,12 +221,12 @@ struct StandardFormatter {
Pointer,
};
static constexpr size_t value_not_set = 0;
static constexpr size_t value_from_next_arg = NumericLimits<size_t>::max();
static constexpr size_t value_from_arg = NumericLimits<size_t>::max() - max_format_arguments - 1;
static constexpr size_t value_not_set = NumericLimits<size_t>::max();
static constexpr size_t value_from_next_arg = NumericLimits<size_t>::max() - 1;
static constexpr size_t value_from_arg = NumericLimits<size_t>::max() - max_format_arguments - 2;
Align m_align = Align::Default;
Sign m_sign = Sign::NegativeOnly;
FormatBuilder::Align m_align = FormatBuilder::Align::Default;
FormatBuilder::SignMode m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
Mode m_mode = Mode::Default;
bool m_alternative_form = false;
char m_fill = ' ';
@ -161,7 +234,7 @@ struct StandardFormatter {
size_t m_width = value_not_set;
size_t m_precision = value_not_set;
void parse(FormatterContext&);
void parse(TypeErasedFormatParams&, FormatParser&);
};
template<>
@ -172,7 +245,7 @@ struct Formatter<StringView> : StandardFormatter {
{
}
void format(StringBuilder& builder, StringView value, FormatterContext&);
void format(TypeErasedFormatParams&, FormatBuilder&, StringView value);
};
template<>
struct Formatter<const char*> : Formatter<StringView> {
@ -195,32 +268,24 @@ struct Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type> : StandardFor
{
}
void format(StringBuilder&, T value, FormatterContext&);
void format(TypeErasedFormatParams&, FormatBuilder&, T value);
};
template<typename T>
struct Formatter<T*> : StandardFormatter {
void format(StringBuilder& builder, T* value, FormatterContext& context)
void format(TypeErasedFormatParams& params, FormatBuilder& builder, T* value)
{
Formatter<FlatPtr> formatter { *this };
formatter.format(builder, reinterpret_cast<FlatPtr>(value), context);
formatter.format(params, builder, reinterpret_cast<FlatPtr>(value));
}
};
template<>
struct Formatter<bool> : StandardFormatter {
void format(StringBuilder&, bool value, FormatterContext&);
void format(TypeErasedFormatParams&, FormatBuilder&, bool value);
};
template<typename... Parameters>
Array<TypeErasedParameter, sizeof...(Parameters)> make_type_erased_parameters(const Parameters&... parameters)
{
static_assert(sizeof...(Parameters) <= max_format_arguments);
return { TypeErasedParameter { &parameters, TypeErasedParameter::get_type<Parameters>(), Detail::Format::format_value<Parameters> }... };
}
void vformat(StringBuilder& builder, StringView fmtstr, Span<const TypeErasedParameter>);
void vformat(const LogStream& stream, StringView fmtstr, Span<const TypeErasedParameter>);
void vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams);
void vformat(const LogStream& stream, StringView fmtstr, TypeErasedFormatParams);
} // namespace AK