2020-09-19 13:47:35 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2020, the SerenityOS developers.
|
|
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-09-19 13:47:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2021-02-22 02:37:24 +03:30
|
|
|
#include <AK/CheckedFormatString.h>
|
|
|
|
|
|
2021-01-17 11:52:04 +03:30
|
|
|
#include <AK/AllOf.h>
|
|
|
|
|
#include <AK/AnyOf.h>
|
2021-11-16 01:15:21 +01:00
|
|
|
#include <AK/Error.h>
|
|
|
|
|
#include <AK/Forward.h>
|
2020-12-30 12:14:15 +01:00
|
|
|
#include <AK/Optional.h>
|
2020-09-22 13:05:40 +02:00
|
|
|
#include <AK/StringView.h>
|
2024-06-17 23:12:53 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2020-09-23 13:21:18 +02:00
|
|
|
|
2020-09-19 13:47:35 +02:00
|
|
|
namespace AK {
|
|
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
class TypeErasedFormatParams;
|
|
|
|
|
class FormatParser;
|
|
|
|
|
class FormatBuilder;
|
|
|
|
|
|
2020-09-19 13:47:35 +02:00
|
|
|
template<typename T, typename = void>
|
2020-10-07 14:01:59 +02:00
|
|
|
struct Formatter {
|
|
|
|
|
using __no_formatter_defined = void;
|
|
|
|
|
};
|
2020-09-19 13:47:35 +02:00
|
|
|
|
2023-01-13 02:19:40 +00:00
|
|
|
enum AllowDebugOnlyFormatters {
|
|
|
|
|
No,
|
|
|
|
|
Yes
|
|
|
|
|
};
|
|
|
|
|
|
2021-07-06 18:55:36 +02:00
|
|
|
template<typename T, typename = void>
|
|
|
|
|
inline constexpr bool HasFormatter = true;
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
inline constexpr bool HasFormatter<T, typename Formatter<T>::__no_formatter_defined> = false;
|
|
|
|
|
|
2023-01-13 02:19:40 +00:00
|
|
|
template<typename Formatter>
|
|
|
|
|
inline constexpr bool is_debug_only_formatter()
|
|
|
|
|
{
|
|
|
|
|
constexpr bool has_is_debug_only = requires(Formatter const& formatter) { formatter.is_debug_only(); };
|
|
|
|
|
if constexpr (has_is_debug_only)
|
|
|
|
|
return Formatter::is_debug_only();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-10 19:33:37 +03:30
|
|
|
template<typename T>
|
|
|
|
|
concept Formattable = HasFormatter<T>;
|
|
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
constexpr size_t max_format_arguments = 256;
|
|
|
|
|
|
2025-05-24 09:06:42 +02:00
|
|
|
template<typename T>
|
|
|
|
|
ErrorOr<void> __format_value(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser, void const* value)
|
|
|
|
|
{
|
|
|
|
|
Formatter<T> formatter;
|
|
|
|
|
|
|
|
|
|
formatter.parse(params, parser);
|
|
|
|
|
return formatter.format(builder, *static_cast<T const*>(value));
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 13:11:29 +02:00
|
|
|
struct TypeErasedParameter {
|
2020-09-27 18:09:14 +02:00
|
|
|
enum class Type {
|
2025-05-24 09:06:42 +02:00
|
|
|
UnsignedInteger,
|
|
|
|
|
SignedInteger,
|
|
|
|
|
Boolean,
|
|
|
|
|
Character,
|
|
|
|
|
Float,
|
|
|
|
|
Double,
|
|
|
|
|
StringView,
|
|
|
|
|
CString,
|
|
|
|
|
CustomType
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CustomType {
|
|
|
|
|
void const* value;
|
|
|
|
|
ErrorOr<void> (*formatter)(TypeErasedFormatParams&, FormatBuilder&, FormatParser&, void const* value);
|
2020-09-27 18:09:14 +02:00
|
|
|
};
|
|
|
|
|
|
2025-05-24 09:06:42 +02:00
|
|
|
template<typename T>
|
|
|
|
|
static bool const IsChar = IsOneOf<T, char, wchar_t, char8_t, char16_t, char32_t>;
|
|
|
|
|
|
|
|
|
|
template<Unsigned U>
|
|
|
|
|
explicit constexpr TypeErasedParameter(U const& value)
|
|
|
|
|
requires(!IsChar<U> && sizeof(U) <= sizeof(u64))
|
|
|
|
|
: value { .as_unsigned = value }
|
|
|
|
|
, type { Type::UnsignedInteger }
|
2020-12-20 17:00:50 +01:00
|
|
|
{
|
2025-05-24 09:06:42 +02:00
|
|
|
}
|
2020-12-20 17:00:50 +01:00
|
|
|
|
2025-05-24 09:06:42 +02:00
|
|
|
template<Signed I>
|
|
|
|
|
explicit constexpr TypeErasedParameter(I const& value)
|
|
|
|
|
requires(!IsChar<I> && sizeof(I) <= sizeof(i64))
|
|
|
|
|
: value { .as_signed = value }
|
|
|
|
|
, type { Type::SignedInteger }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(bool const& value)
|
|
|
|
|
: value { .as_bool = value }
|
|
|
|
|
, type { Type::Boolean }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(char const& value)
|
|
|
|
|
: value { .as_char = value }
|
|
|
|
|
, type { Type::Character }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(float const& value)
|
|
|
|
|
: value { .as_float = value }
|
|
|
|
|
, type { Type::Float }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(double const& value)
|
|
|
|
|
: value { .as_double = value }
|
|
|
|
|
, type { Type::Double }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(StringView const& value)
|
|
|
|
|
: value { .as_string_view = value }
|
|
|
|
|
, type { Type::StringView }
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit constexpr TypeErasedParameter(char const* value)
|
|
|
|
|
: value { .as_c_string = value }
|
|
|
|
|
, type { Type::CString }
|
|
|
|
|
{
|
2020-12-20 17:00:50 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-27 18:09:14 +02:00
|
|
|
template<typename T>
|
2025-05-24 09:06:42 +02:00
|
|
|
explicit constexpr TypeErasedParameter(T const& value)
|
|
|
|
|
: value { .as_custom_type = { &value, __format_value<T> } }
|
|
|
|
|
, type { Type::CustomType }
|
2020-09-27 18:09:14 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-31 17:11:58 -06:00
|
|
|
template<typename Visitor>
|
|
|
|
|
constexpr auto visit(Visitor&& visitor) const
|
2021-04-21 13:47:03 -06:00
|
|
|
{
|
2021-10-31 17:11:58 -06:00
|
|
|
switch (type) {
|
2025-05-24 09:06:42 +02:00
|
|
|
case Type::UnsignedInteger:
|
|
|
|
|
return visitor(value.as_unsigned);
|
|
|
|
|
case Type::SignedInteger:
|
|
|
|
|
return visitor(value.as_signed);
|
|
|
|
|
case Type::Boolean:
|
|
|
|
|
return visitor(value.as_bool);
|
|
|
|
|
case Type::Character:
|
|
|
|
|
return visitor(value.as_char);
|
|
|
|
|
case Type::Float:
|
|
|
|
|
return visitor(value.as_float);
|
|
|
|
|
case Type::Double:
|
|
|
|
|
return visitor(value.as_double);
|
|
|
|
|
case Type::StringView:
|
|
|
|
|
return visitor(value.as_string_view);
|
|
|
|
|
case Type::CString:
|
|
|
|
|
return visitor(value.as_c_string);
|
|
|
|
|
case Type::CustomType:
|
|
|
|
|
return visitor(value.as_custom_type);
|
2021-10-31 17:11:58 -06:00
|
|
|
}
|
2025-05-24 09:06:42 +02:00
|
|
|
VERIFY_NOT_REACHED();
|
2021-10-31 17:11:58 -06:00
|
|
|
}
|
2021-04-21 13:47:03 -06:00
|
|
|
|
2021-10-31 17:11:58 -06:00
|
|
|
constexpr size_t to_size() const
|
|
|
|
|
{
|
2025-05-24 09:06:42 +02:00
|
|
|
return visit([]<typename T>(T value) -> size_t {
|
|
|
|
|
if constexpr (IsSame<T, u64>)
|
|
|
|
|
return static_cast<size_t>(value);
|
|
|
|
|
|
|
|
|
|
if constexpr (IsSame<T, i64>) {
|
2023-02-12 11:07:40 -07:00
|
|
|
VERIFY(value >= 0);
|
2025-05-24 09:06:42 +02:00
|
|
|
return static_cast<size_t>(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TODO();
|
2021-10-31 17:11:58 -06:00
|
|
|
});
|
2021-04-21 13:47:03 -06:00
|
|
|
}
|
2020-12-30 12:14:15 +01:00
|
|
|
|
2025-05-24 09:06:42 +02:00
|
|
|
union {
|
|
|
|
|
u64 as_unsigned;
|
|
|
|
|
i64 as_signed;
|
|
|
|
|
bool as_bool;
|
|
|
|
|
char as_char;
|
|
|
|
|
float as_float;
|
|
|
|
|
double as_double;
|
|
|
|
|
StringView as_string_view;
|
|
|
|
|
char const* as_c_string;
|
|
|
|
|
CustomType as_custom_type;
|
|
|
|
|
} value;
|
2020-09-27 18:09:14 +02:00
|
|
|
Type type;
|
2020-09-28 11:44:24 +02:00
|
|
|
};
|
|
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
class FormatBuilder {
|
|
|
|
|
public:
|
|
|
|
|
enum class Align {
|
|
|
|
|
Default,
|
|
|
|
|
Left,
|
|
|
|
|
Center,
|
|
|
|
|
Right,
|
|
|
|
|
};
|
|
|
|
|
enum class SignMode {
|
|
|
|
|
OnlyIfNeeded,
|
|
|
|
|
Always,
|
|
|
|
|
Reserved,
|
|
|
|
|
Default = OnlyIfNeeded,
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-18 01:32:20 +01:00
|
|
|
enum class RealNumberDisplayMode {
|
|
|
|
|
FixedPoint,
|
|
|
|
|
General,
|
|
|
|
|
Default = General,
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
explicit FormatBuilder(StringBuilder& builder)
|
|
|
|
|
: m_builder(builder)
|
2020-09-28 11:44:24 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_padding(char fill, size_t amount);
|
2020-10-02 15:21:30 +02:00
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_literal(StringView value);
|
2020-10-02 15:21:30 +02:00
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_string(
|
2020-10-02 15:21:30 +02:00
|
|
|
StringView value,
|
|
|
|
|
Align align = Align::Left,
|
|
|
|
|
size_t min_width = 0,
|
|
|
|
|
size_t max_width = NumericLimits<size_t>::max(),
|
|
|
|
|
char fill = ' ');
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_u64(
|
2020-10-02 15:21:30 +02:00
|
|
|
u64 value,
|
|
|
|
|
u8 base = 10,
|
|
|
|
|
bool prefix = false,
|
|
|
|
|
bool upper_case = false,
|
|
|
|
|
bool zero_pad = false,
|
2023-03-06 17:31:39 +00:00
|
|
|
bool use_separator = false,
|
2020-10-02 15:21:30 +02:00
|
|
|
Align align = Align::Right,
|
|
|
|
|
size_t min_width = 0,
|
|
|
|
|
char fill = ' ',
|
|
|
|
|
SignMode sign_mode = SignMode::OnlyIfNeeded,
|
|
|
|
|
bool is_negative = false);
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_i64(
|
2020-10-02 15:21:30 +02:00
|
|
|
i64 value,
|
|
|
|
|
u8 base = 10,
|
|
|
|
|
bool prefix = false,
|
|
|
|
|
bool upper_case = false,
|
|
|
|
|
bool zero_pad = false,
|
2023-03-06 17:31:39 +00:00
|
|
|
bool use_separator = false,
|
2020-10-02 15:21:30 +02:00
|
|
|
Align align = Align::Right,
|
|
|
|
|
size_t min_width = 0,
|
|
|
|
|
char fill = ' ',
|
|
|
|
|
SignMode sign_mode = SignMode::OnlyIfNeeded);
|
|
|
|
|
|
2021-12-27 18:23:04 -07:00
|
|
|
ErrorOr<void> put_fixed_point(
|
2023-02-18 11:31:59 -05:00
|
|
|
bool is_negative,
|
2021-12-27 18:23:04 -07:00
|
|
|
i64 integer_value,
|
|
|
|
|
u64 fraction_value,
|
|
|
|
|
u64 fraction_one,
|
2023-08-13 15:34:00 +00:00
|
|
|
size_t precision,
|
2021-12-27 18:23:04 -07:00
|
|
|
u8 base = 10,
|
|
|
|
|
bool upper_case = false,
|
|
|
|
|
bool zero_pad = false,
|
2023-03-06 17:31:39 +00:00
|
|
|
bool use_separator = false,
|
2021-12-27 18:23:04 -07:00
|
|
|
Align align = Align::Right,
|
|
|
|
|
size_t min_width = 0,
|
2023-08-13 15:34:00 +00:00
|
|
|
size_t fraction_max_width = 6,
|
2021-12-27 18:23:04 -07:00
|
|
|
char fill = ' ',
|
2023-08-13 15:34:00 +00:00
|
|
|
SignMode sign_mode = SignMode::OnlyIfNeeded);
|
2021-12-27 18:23:04 -07:00
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_f80(
|
2021-05-07 11:32:01 +02:00
|
|
|
long double value,
|
|
|
|
|
u8 base = 10,
|
|
|
|
|
bool upper_case = false,
|
2023-03-06 17:31:39 +00:00
|
|
|
bool use_separator = false,
|
2021-05-07 11:32:01 +02:00
|
|
|
Align align = Align::Right,
|
|
|
|
|
size_t min_width = 0,
|
|
|
|
|
size_t precision = 6,
|
|
|
|
|
char fill = ' ',
|
2022-12-18 01:32:20 +01:00
|
|
|
SignMode sign_mode = SignMode::OnlyIfNeeded,
|
|
|
|
|
RealNumberDisplayMode = RealNumberDisplayMode::Default);
|
2021-05-07 11:32:01 +02:00
|
|
|
|
2023-10-30 23:31:47 +03:30
|
|
|
template<OneOf<f32, f64> T>
|
|
|
|
|
ErrorOr<void> put_f32_or_f64(
|
|
|
|
|
T value,
|
2020-11-09 11:34:44 +01:00
|
|
|
u8 base = 10,
|
|
|
|
|
bool upper_case = false,
|
2021-06-19 17:00:31 +03:00
|
|
|
bool zero_pad = false,
|
2023-03-06 17:31:39 +00:00
|
|
|
bool use_separator = false,
|
2020-11-09 11:34:44 +01:00
|
|
|
Align align = Align::Right,
|
|
|
|
|
size_t min_width = 0,
|
2023-10-30 23:31:47 +03:30
|
|
|
Optional<size_t> precision = {},
|
2020-11-09 11:34:44 +01:00
|
|
|
char fill = ' ',
|
2022-12-18 01:32:20 +01:00
|
|
|
SignMode sign_mode = SignMode::OnlyIfNeeded,
|
|
|
|
|
RealNumberDisplayMode = RealNumberDisplayMode::Default);
|
2020-11-09 11:34:44 +01:00
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> put_hexdump(
|
2021-06-17 13:11:00 +04:30
|
|
|
ReadonlyBytes,
|
|
|
|
|
size_t width,
|
|
|
|
|
char fill = ' ');
|
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
StringBuilder const& builder() const
|
2020-11-09 11:34:44 +01:00
|
|
|
{
|
|
|
|
|
return m_builder;
|
|
|
|
|
}
|
2020-10-02 15:21:30 +02:00
|
|
|
StringBuilder& builder() { return m_builder; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
StringBuilder& m_builder;
|
2023-10-30 23:31:47 +03:30
|
|
|
|
|
|
|
|
ErrorOr<void> put_f64_with_precision(
|
|
|
|
|
double value,
|
|
|
|
|
u8 base,
|
|
|
|
|
bool upper_case,
|
|
|
|
|
bool zero_pad,
|
|
|
|
|
bool use_separator,
|
|
|
|
|
Align align,
|
|
|
|
|
size_t min_width,
|
|
|
|
|
size_t precision,
|
|
|
|
|
char fill,
|
|
|
|
|
SignMode sign_mode,
|
|
|
|
|
RealNumberDisplayMode);
|
2020-10-02 15:21:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TypeErasedFormatParams {
|
|
|
|
|
public:
|
2023-07-08 16:08:21 +02:00
|
|
|
TypeErasedFormatParams(u32 size)
|
|
|
|
|
: m_size(size)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReadonlySpan<TypeErasedParameter> parameters() const { return { m_parameters, m_size }; }
|
2020-09-28 11:44:24 +02:00
|
|
|
|
|
|
|
|
size_t take_next_index() { return m_next_index++; }
|
|
|
|
|
|
|
|
|
|
private:
|
2023-07-08 16:08:21 +02:00
|
|
|
u32 m_size { 0 };
|
|
|
|
|
u32 m_next_index { 0 };
|
|
|
|
|
TypeErasedParameter m_parameters[0];
|
2020-09-25 13:11:29 +02:00
|
|
|
};
|
|
|
|
|
|
2023-01-13 02:19:40 +00:00
|
|
|
template<AllowDebugOnlyFormatters allow_debug_formatters, typename... Parameters>
|
2020-10-02 15:21:30 +02:00
|
|
|
class VariadicFormatParams : public TypeErasedFormatParams {
|
|
|
|
|
public:
|
|
|
|
|
static_assert(sizeof...(Parameters) <= max_format_arguments);
|
2020-09-19 13:47:35 +02:00
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
explicit VariadicFormatParams(Parameters const&... parameters)
|
2023-07-08 16:08:21 +02:00
|
|
|
: TypeErasedFormatParams(sizeof...(Parameters))
|
2025-05-24 09:06:42 +02:00
|
|
|
, m_parameter_storage { TypeErasedParameter { parameters }... }
|
2020-10-02 15:21:30 +02:00
|
|
|
{
|
2023-01-13 02:19:40 +00:00
|
|
|
constexpr bool any_debug_formatters = (is_debug_only_formatter<Formatter<Parameters>>() || ...);
|
|
|
|
|
static_assert(!any_debug_formatters || allow_debug_formatters == AllowDebugOnlyFormatters::Yes,
|
|
|
|
|
"You are attempting to use a debug-only formatter outside of a debug log! Maybe one of your format values is an ErrorOr<T>?");
|
2020-10-02 15:21:30 +02:00
|
|
|
}
|
2020-09-19 13:47:35 +02:00
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
private:
|
2023-07-08 16:08:21 +02:00
|
|
|
TypeErasedParameter m_parameter_storage[sizeof...(Parameters)];
|
2020-10-02 15:21:30 +02:00
|
|
|
};
|
2020-09-25 13:11:29 +02:00
|
|
|
|
2020-10-06 13:32:00 +02:00
|
|
|
// We use the same format for most types for consistency. This is taken directly from
|
|
|
|
|
// std::format. One difference is that we are not counting the width or sign towards the
|
|
|
|
|
// total width when calculating zero padding for numbers.
|
2020-09-25 13:11:29 +02:00
|
|
|
// https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
|
|
|
|
|
struct StandardFormatter {
|
|
|
|
|
enum class Mode {
|
|
|
|
|
Default,
|
|
|
|
|
Binary,
|
2020-09-26 15:26:14 +02:00
|
|
|
BinaryUppercase,
|
2020-09-25 13:11:29 +02:00
|
|
|
Decimal,
|
|
|
|
|
Octal,
|
|
|
|
|
Hexadecimal,
|
2020-09-26 15:26:14 +02:00
|
|
|
HexadecimalUppercase,
|
2020-09-25 13:11:29 +02:00
|
|
|
Character,
|
|
|
|
|
String,
|
|
|
|
|
Pointer,
|
2022-12-18 01:04:18 +01:00
|
|
|
FixedPoint,
|
2020-11-09 11:34:44 +01:00
|
|
|
Hexfloat,
|
|
|
|
|
HexfloatUppercase,
|
2021-06-17 13:11:00 +04:30
|
|
|
HexDump,
|
2020-09-25 13:11:29 +02:00
|
|
|
};
|
|
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
FormatBuilder::Align m_align = FormatBuilder::Align::Default;
|
|
|
|
|
FormatBuilder::SignMode m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
|
2020-09-25 13:11:29 +02:00
|
|
|
Mode m_mode = Mode::Default;
|
|
|
|
|
bool m_alternative_form = false;
|
2023-03-06 17:31:39 +00:00
|
|
|
bool m_use_separator = false;
|
2020-09-25 13:11:29 +02:00
|
|
|
char m_fill = ' ';
|
|
|
|
|
bool m_zero_pad = false;
|
2020-12-30 12:14:15 +01:00
|
|
|
Optional<size_t> m_width;
|
|
|
|
|
Optional<size_t> m_precision;
|
2020-09-25 13:11:29 +02:00
|
|
|
|
2020-10-02 15:21:30 +02:00
|
|
|
void parse(TypeErasedFormatParams&, FormatParser&);
|
2020-09-19 13:47:35 +02:00
|
|
|
};
|
|
|
|
|
|
2022-03-17 11:29:46 -06:00
|
|
|
template<Integral T>
|
|
|
|
|
struct Formatter<T> : StandardFormatter {
|
2021-01-10 16:29:28 -07:00
|
|
|
Formatter() = default;
|
2020-10-06 13:57:20 +02:00
|
|
|
explicit Formatter(StandardFormatter formatter)
|
2021-10-31 17:13:05 -06:00
|
|
|
: StandardFormatter(move(formatter))
|
2020-10-06 13:57:20 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, T);
|
2020-10-06 13:57:20 +02:00
|
|
|
};
|
|
|
|
|
|
2020-09-19 13:47:35 +02:00
|
|
|
template<>
|
2020-09-25 13:11:29 +02:00
|
|
|
struct Formatter<StringView> : StandardFormatter {
|
2021-01-10 16:29:28 -07:00
|
|
|
Formatter() = default;
|
2020-09-30 13:26:24 +02:00
|
|
|
explicit Formatter(StandardFormatter formatter)
|
2021-10-31 17:13:05 -06:00
|
|
|
: StandardFormatter(move(formatter))
|
2020-09-30 13:26:24 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, StringView);
|
2020-09-23 13:21:18 +02:00
|
|
|
};
|
2021-06-17 13:11:00 +04:30
|
|
|
|
2022-12-08 08:08:08 -05:00
|
|
|
template<typename T>
|
|
|
|
|
requires(HasFormatter<T>)
|
2023-02-05 19:02:54 +00:00
|
|
|
struct Formatter<ReadonlySpan<T>> : StandardFormatter {
|
2021-07-06 18:55:36 +02:00
|
|
|
Formatter() = default;
|
|
|
|
|
explicit Formatter(StandardFormatter formatter)
|
2021-10-31 17:13:05 -06:00
|
|
|
: StandardFormatter(move(formatter))
|
2021-07-06 18:55:36 +02:00
|
|
|
{
|
|
|
|
|
}
|
2022-12-08 08:08:08 -05:00
|
|
|
|
2023-02-05 19:02:54 +00:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, ReadonlySpan<T> value)
|
2021-07-06 18:55:36 +02:00
|
|
|
{
|
|
|
|
|
if (m_mode == Mode::Pointer) {
|
|
|
|
|
Formatter<FlatPtr> formatter { *this };
|
2021-11-16 01:15:21 +01:00
|
|
|
TRY(formatter.format(builder, reinterpret_cast<FlatPtr>(value.data())));
|
|
|
|
|
return {};
|
2021-07-06 18:55:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_sign_mode != FormatBuilder::SignMode::Default)
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
if (m_alternative_form)
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
if (m_zero_pad)
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
if (m_mode != Mode::Default)
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
if (m_width.has_value() && m_precision.has_value())
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
|
|
|
|
|
m_width = m_width.value_or(0);
|
|
|
|
|
m_precision = m_precision.value_or(NumericLimits<size_t>::max());
|
|
|
|
|
|
|
|
|
|
Formatter<T> content_fmt;
|
2021-11-16 01:15:21 +01:00
|
|
|
TRY(builder.put_literal("[ "sv));
|
2021-07-06 18:55:36 +02:00
|
|
|
bool first = true;
|
|
|
|
|
for (auto& content : value) {
|
2021-07-17 16:27:12 -06:00
|
|
|
if (!first) {
|
2021-11-16 01:15:21 +01:00
|
|
|
TRY(builder.put_literal(", "sv));
|
2021-07-17 16:27:12 -06:00
|
|
|
content_fmt = Formatter<T> {};
|
|
|
|
|
}
|
2021-07-06 18:55:36 +02:00
|
|
|
first = false;
|
2021-11-16 01:15:21 +01:00
|
|
|
TRY(content_fmt.format(builder, content));
|
2021-07-06 18:55:36 +02:00
|
|
|
}
|
2021-11-16 01:15:21 +01:00
|
|
|
TRY(builder.put_literal(" ]"sv));
|
|
|
|
|
return {};
|
2021-07-06 18:55:36 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-08 08:08:08 -05:00
|
|
|
template<typename T>
|
|
|
|
|
requires(HasFormatter<T>)
|
2023-02-05 19:02:54 +00:00
|
|
|
struct Formatter<Span<T>> : Formatter<ReadonlySpan<T>> {
|
2022-12-08 08:08:08 -05:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, Span<T> value)
|
|
|
|
|
{
|
2023-02-05 19:02:54 +00:00
|
|
|
return Formatter<ReadonlySpan<T>>::format(builder, value);
|
2022-12-08 08:08:08 -05:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename T, size_t inline_capacity>
|
|
|
|
|
requires(HasFormatter<T>)
|
2023-02-05 19:02:54 +00:00
|
|
|
struct Formatter<Vector<T, inline_capacity>> : Formatter<ReadonlySpan<T>> {
|
2022-12-08 08:08:08 -05:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, Vector<T, inline_capacity> const& value)
|
|
|
|
|
{
|
2023-02-05 19:02:54 +00:00
|
|
|
return Formatter<ReadonlySpan<T>>::format(builder, value.span());
|
2022-12-08 08:08:08 -05:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-17 13:11:00 +04:30
|
|
|
template<>
|
|
|
|
|
struct Formatter<ReadonlyBytes> : Formatter<StringView> {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, ReadonlyBytes value)
|
2021-06-17 13:11:00 +04:30
|
|
|
{
|
|
|
|
|
if (m_mode == Mode::Pointer) {
|
|
|
|
|
Formatter<FlatPtr> formatter { *this };
|
2021-11-16 01:15:21 +01:00
|
|
|
return formatter.format(builder, reinterpret_cast<FlatPtr>(value.data()));
|
|
|
|
|
}
|
|
|
|
|
if (m_mode == Mode::Default || m_mode == Mode::HexDump) {
|
2021-06-17 13:11:00 +04:30
|
|
|
m_mode = Mode::HexDump;
|
2021-11-16 01:15:21 +01:00
|
|
|
return Formatter<StringView>::format(builder, value);
|
2021-06-17 13:11:00 +04:30
|
|
|
}
|
2021-11-16 01:15:21 +01:00
|
|
|
return Formatter<StringView>::format(builder, value);
|
2021-06-17 13:11:00 +04:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
struct Formatter<Bytes> : Formatter<ReadonlyBytes> {
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-11 19:59:54 +00:00
|
|
|
// FIXME: Printing raw char pointers is inherently dangerous. Remove this and
|
|
|
|
|
// its users and prefer StringView over it.
|
2020-09-23 16:31:34 +02:00
|
|
|
template<>
|
2022-04-01 20:58:27 +03:00
|
|
|
struct Formatter<char const*> : Formatter<StringView> {
|
|
|
|
|
ErrorOr<void> format(FormatBuilder& builder, char const* value)
|
2020-10-06 13:57:20 +02:00
|
|
|
{
|
|
|
|
|
if (m_mode == Mode::Pointer) {
|
|
|
|
|
Formatter<FlatPtr> formatter { *this };
|
2021-11-16 01:15:21 +01:00
|
|
|
return formatter.format(builder, reinterpret_cast<FlatPtr>(value));
|
2020-10-06 13:57:20 +02:00
|
|
|
}
|
2022-07-11 19:59:54 +00:00
|
|
|
|
|
|
|
|
return Formatter<StringView>::format(builder, value != nullptr ? StringView { value, __builtin_strlen(value) } : "(null)"sv);
|
2020-10-06 13:57:20 +02:00
|
|
|
}
|
2020-09-23 16:31:34 +02:00
|
|
|
};
|
|
|
|
|
template<>
|
2022-04-01 20:58:27 +03:00
|
|
|
struct Formatter<char*> : Formatter<char const*> {
|
2020-09-23 16:31:34 +02:00
|
|
|
};
|
2020-09-23 13:21:18 +02:00
|
|
|
template<size_t Size>
|
2022-04-01 20:58:27 +03:00
|
|
|
struct Formatter<char[Size]> : Formatter<char const*> {
|
2020-09-19 13:47:35 +02:00
|
|
|
};
|
|
|
|
|
template<>
|
2023-12-16 17:49:34 +03:30
|
|
|
struct Formatter<ByteString> : Formatter<StringView> {
|
2020-09-19 13:47:35 +02:00
|
|
|
};
|
|
|
|
|
|
2020-09-30 14:38:47 +02:00
|
|
|
template<typename T>
|
|
|
|
|
struct Formatter<T*> : StandardFormatter {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, T* value)
|
2020-09-30 14:38:47 +02:00
|
|
|
{
|
2020-10-07 12:47:35 +02:00
|
|
|
if (m_mode == Mode::Default)
|
|
|
|
|
m_mode = Mode::Pointer;
|
|
|
|
|
|
2020-09-30 14:38:47 +02:00
|
|
|
Formatter<FlatPtr> formatter { *this };
|
2021-11-16 01:15:21 +01:00
|
|
|
return formatter.format(builder, reinterpret_cast<FlatPtr>(value));
|
2020-09-30 14:38:47 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-04 13:49:19 +02:00
|
|
|
template<>
|
2020-10-07 14:25:19 +02:00
|
|
|
struct Formatter<char> : StandardFormatter {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, char);
|
2020-10-04 13:49:19 +02:00
|
|
|
};
|
2020-09-30 13:26:24 +02:00
|
|
|
template<>
|
2025-06-13 10:15:08 -04:00
|
|
|
struct Formatter<char16_t> : StandardFormatter {
|
|
|
|
|
ErrorOr<void> format(FormatBuilder&, char16_t);
|
|
|
|
|
};
|
|
|
|
|
template<>
|
2025-05-18 16:05:41 -07:00
|
|
|
struct Formatter<char32_t> : StandardFormatter {
|
2025-06-13 10:15:08 -04:00
|
|
|
ErrorOr<void> format(FormatBuilder&, char32_t);
|
2021-09-21 23:07:03 +02:00
|
|
|
};
|
|
|
|
|
template<>
|
2020-09-30 13:26:24 +02:00
|
|
|
struct Formatter<bool> : StandardFormatter {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, bool);
|
2020-09-30 13:26:24 +02:00
|
|
|
};
|
|
|
|
|
|
2020-11-09 11:34:44 +01:00
|
|
|
template<>
|
|
|
|
|
struct Formatter<float> : StandardFormatter {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, float value);
|
2020-11-09 11:34:44 +01:00
|
|
|
};
|
|
|
|
|
template<>
|
|
|
|
|
struct Formatter<double> : StandardFormatter {
|
2021-01-10 16:29:28 -07:00
|
|
|
Formatter() = default;
|
2020-11-09 11:34:44 +01:00
|
|
|
explicit Formatter(StandardFormatter formatter)
|
|
|
|
|
: StandardFormatter(formatter)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, double);
|
2020-11-09 11:34:44 +01:00
|
|
|
};
|
2021-05-07 11:32:01 +02:00
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
struct Formatter<long double> : StandardFormatter {
|
|
|
|
|
Formatter() = default;
|
|
|
|
|
explicit Formatter(StandardFormatter formatter)
|
|
|
|
|
: StandardFormatter(formatter)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder&, long double value);
|
2021-05-07 11:32:01 +02:00
|
|
|
};
|
2020-11-09 11:34:44 +01:00
|
|
|
|
2024-11-09 14:25:05 -06:00
|
|
|
template<>
|
|
|
|
|
struct Formatter<f16> : StandardFormatter {
|
|
|
|
|
Formatter() = default;
|
|
|
|
|
explicit Formatter(StandardFormatter formatter)
|
|
|
|
|
: StandardFormatter(formatter)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorOr<void> format(FormatBuilder&, f16 value);
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-01 23:34:00 +01:00
|
|
|
template<>
|
2022-12-13 10:29:30 +03:30
|
|
|
struct Formatter<nullptr_t> : Formatter<FlatPtr> {
|
|
|
|
|
ErrorOr<void> format(FormatBuilder& builder, nullptr_t)
|
2021-01-01 23:34:00 +01:00
|
|
|
{
|
|
|
|
|
if (m_mode == Mode::Default)
|
|
|
|
|
m_mode = Mode::Pointer;
|
|
|
|
|
|
|
|
|
|
return Formatter<FlatPtr>::format(builder, 0);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-06-17 15:48:16 +01:00
|
|
|
template<typename T>
|
|
|
|
|
struct Formatter<Checked<T>> : Formatter<T> {
|
|
|
|
|
ErrorOr<void> format(FormatBuilder& builder, Checked<T> value)
|
|
|
|
|
{
|
|
|
|
|
if (value.has_overflow())
|
|
|
|
|
return builder.put_string("{ OVERFLOW }"sv);
|
|
|
|
|
return Formatter<T>::format(builder, value.value());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> vformat(StringBuilder&, StringView fmtstr, TypeErasedFormatParams&);
|
2020-09-22 13:11:05 +02:00
|
|
|
|
2021-08-30 02:58:22 -07:00
|
|
|
void vout(FILE*, StringView fmtstr, TypeErasedFormatParams&, bool newline = false);
|
2020-10-04 15:35:43 +02:00
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
void out(FILE* file, CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
2021-08-30 02:58:22 -07:00
|
|
|
{
|
2023-01-13 02:19:40 +00:00
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
2021-08-30 02:58:22 -07:00
|
|
|
vout(file, fmtstr.view(), variadic_format_params);
|
|
|
|
|
}
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2020-10-07 14:00:59 +02:00
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
void outln(FILE* file, CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
2021-08-30 02:58:22 -07:00
|
|
|
{
|
2023-01-13 02:19:40 +00:00
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
2021-08-30 02:58:22 -07:00
|
|
|
vout(file, fmtstr.view(), variadic_format_params, true);
|
|
|
|
|
}
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2020-10-15 13:46:00 +02:00
|
|
|
inline void outln(FILE* file) { fputc('\n', file); }
|
2020-10-04 15:35:43 +02:00
|
|
|
|
2024-06-17 23:12:53 +01:00
|
|
|
#ifndef AK_OS_ANDROID
|
2020-10-15 13:46:00 +02:00
|
|
|
template<typename... Parameters>
|
2023-09-13 23:19:25 -06:00
|
|
|
void out(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
out(stdout, move(fmtstr), parameters...);
|
|
|
|
|
}
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2020-10-15 13:46:00 +02:00
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
void outln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters) { outln(stdout, move(fmtstr), parameters...); }
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2020-10-15 13:46:00 +02:00
|
|
|
inline void outln() { outln(stdout); }
|
2020-10-04 15:35:43 +02:00
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
void warn(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
2021-04-15 22:06:18 +02:00
|
|
|
{
|
|
|
|
|
out(stderr, move(fmtstr), parameters...);
|
|
|
|
|
}
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2020-10-07 14:00:59 +02:00
|
|
|
template<typename... Parameters>
|
2023-07-22 08:59:08 -04:00
|
|
|
void warnln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters) { outln(stderr, move(fmtstr), parameters...); }
|
2021-02-22 02:37:24 +03:30
|
|
|
|
2023-07-22 08:59:08 -04:00
|
|
|
inline void warnln() { outln(stderr); }
|
2024-06-17 23:12:53 +01:00
|
|
|
#else // v Android ^ No Android
|
2023-09-13 23:19:25 -06:00
|
|
|
enum class LogLevel {
|
|
|
|
|
Debug,
|
|
|
|
|
Info,
|
|
|
|
|
Warning,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void vout(LogLevel, StringView fmtstr, TypeErasedFormatParams&, bool newline = false);
|
|
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
|
|
|
|
void out(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
|
|
|
|
vout(LogLevel::Info, fmtstr.view(), variadic_format_params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
|
|
|
|
void outln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
|
|
|
|
vout(LogLevel::Info, fmtstr.view(), variadic_format_params, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void outln() { outln(""); }
|
|
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
|
|
|
|
void warn(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
|
|
|
|
vout(LogLevel::Warning, fmtstr.view(), variadic_format_params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename... Parameters>
|
|
|
|
|
void warnln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
|
|
|
|
vout(LogLevel::Warning, fmtstr.view(), variadic_format_params, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void warnln() { warnln(""); }
|
|
|
|
|
|
|
|
|
|
void set_log_tag_name(char const*);
|
2024-06-17 23:12:53 +01:00
|
|
|
#endif // AK_OS_ANDROID
|
2023-09-13 23:19:25 -06:00
|
|
|
|
2024-06-17 23:12:53 +01:00
|
|
|
#define outln_if(flag, fmt, ...) \
|
|
|
|
|
do { \
|
|
|
|
|
if constexpr (flag) \
|
|
|
|
|
outln(fmt, ##__VA_ARGS__); \
|
|
|
|
|
} while (0)
|
2021-04-15 22:06:18 +02:00
|
|
|
|
2024-06-17 23:12:53 +01:00
|
|
|
#define warnln_if(flag, fmt, ...) \
|
|
|
|
|
do { \
|
|
|
|
|
if constexpr (flag) \
|
|
|
|
|
warnln(fmt, ##__VA_ARGS__); \
|
|
|
|
|
} while (0)
|
2020-10-04 15:35:43 +02:00
|
|
|
|
2025-07-16 15:50:31 +02:00
|
|
|
#define dbgln_if(flag, fmt, ...) \
|
|
|
|
|
do { \
|
|
|
|
|
if constexpr (flag) \
|
|
|
|
|
dbgln(fmt, ##__VA_ARGS__); \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define dbgln_dump(expr) \
|
|
|
|
|
do { \
|
|
|
|
|
dbgln(#expr ": {}", (expr)); \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
2023-07-22 08:59:08 -04:00
|
|
|
void vdbg(StringView fmtstr, TypeErasedFormatParams&, bool newline = false);
|
|
|
|
|
|
2023-05-18 09:49:49 -04:00
|
|
|
template<typename... Parameters>
|
|
|
|
|
void dbg(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
|
|
|
|
{
|
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
|
|
|
|
vdbg(fmtstr.view(), variadic_format_params, false);
|
|
|
|
|
}
|
2020-10-04 15:35:43 +02:00
|
|
|
|
2021-02-24 02:05:43 +03:30
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
void dbgln(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
2021-01-12 22:10:24 +01:00
|
|
|
{
|
2023-01-13 02:19:40 +00:00
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::Yes, Parameters...> variadic_format_params { parameters... };
|
2023-05-18 09:49:49 -04:00
|
|
|
vdbg(fmtstr.view(), variadic_format_params, true);
|
2021-01-12 22:10:24 +01:00
|
|
|
}
|
2021-01-17 11:52:04 +03:30
|
|
|
|
2021-02-24 02:05:43 +03:30
|
|
|
inline void dbgln() { dbgln(""); }
|
2020-10-04 15:35:43 +02:00
|
|
|
|
2021-01-18 17:37:30 +01:00
|
|
|
void set_debug_enabled(bool);
|
2023-12-08 13:52:20 -07:00
|
|
|
void set_rich_debug_enabled(bool);
|
2021-01-18 17:37:30 +01:00
|
|
|
|
2020-10-07 14:01:59 +02:00
|
|
|
template<typename T>
|
|
|
|
|
class FormatIfSupported {
|
|
|
|
|
public:
|
2022-10-17 00:06:11 +02:00
|
|
|
explicit FormatIfSupported(T const& value)
|
2020-10-07 14:01:59 +02:00
|
|
|
: m_value(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 00:06:11 +02:00
|
|
|
T const& value() const { return m_value; }
|
2020-10-07 14:01:59 +02:00
|
|
|
|
|
|
|
|
private:
|
2022-10-17 00:06:11 +02:00
|
|
|
T const& m_value;
|
2020-10-07 14:01:59 +02:00
|
|
|
};
|
|
|
|
|
template<typename T, bool Supported = false>
|
|
|
|
|
struct __FormatIfSupported : Formatter<StringView> {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, FormatIfSupported<T> const&)
|
2020-10-07 14:01:59 +02:00
|
|
|
{
|
2022-07-11 17:32:29 +00:00
|
|
|
return Formatter<StringView>::format(builder, "?"sv);
|
2020-10-07 14:01:59 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct __FormatIfSupported<T, true> : Formatter<T> {
|
2021-11-16 01:15:21 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, FormatIfSupported<T> const& value)
|
2020-10-07 14:01:59 +02:00
|
|
|
{
|
2021-11-16 01:15:21 +01:00
|
|
|
return Formatter<T>::format(builder, value.value());
|
2020-10-07 14:01:59 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template<typename T>
|
2021-04-10 18:29:06 +04:30
|
|
|
struct Formatter<FormatIfSupported<T>> : __FormatIfSupported<T, HasFormatter<T>> {
|
2020-10-07 14:01:59 +02:00
|
|
|
};
|
|
|
|
|
|
2021-01-09 01:00:22 +01:00
|
|
|
// This is a helper class, the idea is that if you want to implement a formatter you can inherit
|
|
|
|
|
// from this class to "break down" the formatting.
|
|
|
|
|
struct FormatString {
|
|
|
|
|
};
|
|
|
|
|
template<>
|
2021-10-21 19:09:38 +02:00
|
|
|
struct Formatter<FormatString> : Formatter<StringView> {
|
2021-01-09 01:00:22 +01:00
|
|
|
template<typename... Parameters>
|
2022-04-01 20:58:27 +03:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, StringView fmtstr, Parameters const&... parameters)
|
2021-01-09 01:00:22 +01:00
|
|
|
{
|
2023-01-13 02:19:40 +00:00
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_params { parameters... };
|
2021-11-16 01:15:21 +01:00
|
|
|
return vformat(builder, fmtstr, variadic_format_params);
|
|
|
|
|
}
|
|
|
|
|
ErrorOr<void> vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
struct Formatter<Error> : Formatter<FormatString> {
|
2025-04-04 09:08:13 +02:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, Error const& error);
|
2021-12-20 11:55:32 +01:00
|
|
|
|
2025-04-04 09:08:13 +02:00
|
|
|
private:
|
|
|
|
|
ErrorOr<void> format_windows_error(FormatBuilder& builder, Error const& error);
|
2021-01-09 01:00:22 +01:00
|
|
|
};
|
|
|
|
|
|
2021-11-26 22:33:04 +01:00
|
|
|
template<typename T, typename ErrorType>
|
|
|
|
|
struct Formatter<ErrorOr<T, ErrorType>> : Formatter<FormatString> {
|
2023-01-13 02:19:40 +00:00
|
|
|
static constexpr bool is_debug_only() { return true; }
|
|
|
|
|
|
2021-11-26 22:33:04 +01:00
|
|
|
ErrorOr<void> format(FormatBuilder& builder, ErrorOr<T, ErrorType> const& error_or)
|
|
|
|
|
{
|
|
|
|
|
if (error_or.is_error())
|
2022-07-11 17:32:29 +00:00
|
|
|
return Formatter<FormatString>::format(builder, "{}"sv, error_or.error());
|
|
|
|
|
return Formatter<FormatString>::format(builder, "{{{}}}"sv, error_or.value());
|
2021-11-26 22:33:04 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-18 18:31:00 +01:00
|
|
|
template<typename T>
|
|
|
|
|
struct Formatter<Optional<T>> : Formatter<FormatString> {
|
|
|
|
|
ErrorOr<void> format(FormatBuilder& builder, Optional<T> const& optional)
|
|
|
|
|
{
|
|
|
|
|
if (optional.has_value())
|
2023-04-28 14:03:44 +03:30
|
|
|
return Formatter<FormatString>::format(builder, "{}"sv, *optional);
|
|
|
|
|
return builder.put_literal("None"sv);
|
2023-04-18 18:31:00 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-09-22 13:11:05 +02:00
|
|
|
} // namespace AK
|
2020-10-04 15:35:43 +02:00
|
|
|
|
2024-11-30 16:29:25 +01:00
|
|
|
#undef AK_HANDLE_UNEXPECTED_ERROR
|
|
|
|
|
#define AK_HANDLE_UNEXPECTED_ERROR(result) \
|
|
|
|
|
if (result.is_error()) [[unlikely]] { \
|
|
|
|
|
if (ak_colorize_output()) { \
|
|
|
|
|
::AK::warn("\033[31;1mUNEXPECTED ERROR\033[0m"); \
|
|
|
|
|
} else { \
|
|
|
|
|
::AK::warn("UNEXPECTED ERROR"); \
|
|
|
|
|
} \
|
|
|
|
|
if constexpr (::AK::HasFormatter<decltype(result.release_error())>) { \
|
|
|
|
|
::AK::warn(": {}", result.release_error()); \
|
|
|
|
|
} \
|
|
|
|
|
::AK::warnln(" at {}:{}", __FILE__, __LINE__); \
|
|
|
|
|
ak_trap(); \
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-26 12:18:30 +01:00
|
|
|
#if USING_AK_GLOBALLY
|
2020-11-09 10:47:19 +01:00
|
|
|
using AK::out;
|
2020-10-04 15:35:43 +02:00
|
|
|
using AK::outln;
|
|
|
|
|
|
2020-11-09 10:47:19 +01:00
|
|
|
using AK::warn;
|
2020-10-04 15:35:43 +02:00
|
|
|
using AK::warnln;
|
|
|
|
|
|
2023-05-18 09:49:49 -04:00
|
|
|
using AK::dbg;
|
2020-10-04 15:35:43 +02:00
|
|
|
using AK::dbgln;
|
2020-10-07 14:01:59 +02:00
|
|
|
|
2021-02-22 02:37:24 +03:30
|
|
|
using AK::CheckedFormatString;
|
2020-10-07 14:01:59 +02:00
|
|
|
using AK::FormatIfSupported;
|
2021-01-09 01:00:22 +01:00
|
|
|
using AK::FormatString;
|
2022-11-26 12:18:30 +01:00
|
|
|
#endif
|