Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/Format.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020, the SerenityOS developers.
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/CharacterTypes.h>
8
#include <AK/Format.h>
9
#include <AK/FormatParser.h>
10
#include <AK/GenericLexer.h>
11
#include <AK/IntegralMath.h>
12
#include <AK/StringBuilder.h>
13
#include <AK/kstdio.h>
14
15
#if defined(AK_OS_SERENITY) && !defined(KERNEL)
16
#    include <serenity.h>
17
#endif
18
19
#if defined(PREKERNEL)
20
#elif defined(KERNEL)
21
#    include <Kernel/Tasks/Process.h>
22
#    include <Kernel/Tasks/Thread.h>
23
#    include <Kernel/Time/TimeManagement.h>
24
#else
25
#    include <AK/LexicalPath.h>
26
#    include <AK/String.h>
27
#    include <AK/StringFloatingPointConversions.h>
28
#    include <math.h>
29
#    include <stdio.h>
30
#    include <string.h>
31
#    include <time.h>
32
#endif
33
34
namespace AK {
35
36
namespace {
37
38
static constexpr size_t use_next_index = NumericLimits<size_t>::max();
39
40
// The worst case is that we have the largest 64-bit value formatted as binary number, this would take
41
// 65 bytes (85 bytes with separators). Choosing a larger power of two won't hurt and is a bit of mitigation against out-of-bounds accesses.
42
static constexpr size_t convert_unsigned_to_string(u64 value, Array<u8, 128>& buffer, u8 base, bool upper_case, bool use_separator)
43
107M
{
44
107M
    VERIFY(base >= 2 && base <= 16);
45
46
107M
    constexpr char const* lowercase_lookup = "0123456789abcdef";
47
107M
    constexpr char const* uppercase_lookup = "0123456789ABCDEF";
48
49
107M
    if (value == 0) {
50
667k
        buffer[0] = '0';
51
667k
        return 1;
52
667k
    }
53
54
106M
    size_t used = 0;
55
106M
    size_t digit_count = 0;
56
320M
    while (value > 0) {
57
213M
        if (upper_case)
58
211M
            buffer[used++] = uppercase_lookup[value % base];
59
1.87M
        else
60
1.87M
            buffer[used++] = lowercase_lookup[value % base];
61
62
213M
        digit_count++;
63
213M
        value /= base;
64
65
213M
        if (use_separator && value > 0 && digit_count % 3 == 0)
66
0
            buffer[used++] = ',';
67
213M
    }
68
69
213M
    for (size_t i = 0; i < used / 2; ++i)
70
106M
        swap(buffer[i], buffer[used - i - 1]);
71
72
106M
    return used;
73
107M
}
74
75
ErrorOr<void> vformat_impl(TypeErasedFormatParams& params, FormatBuilder& builder, FormatParser& parser)
76
274M
{
77
274M
    auto const literal = parser.consume_literal();
78
274M
    TRY(builder.put_literal(literal));
79
80
274M
    FormatParser::FormatSpecifier specifier;
81
274M
    if (!parser.consume_specifier(specifier)) {
82
110M
        VERIFY(parser.is_eof());
83
110M
        return {};
84
110M
    }
85
86
164M
    if (specifier.index == use_next_index)
87
164M
        specifier.index = params.take_next_index();
88
89
164M
    auto& parameter = params.parameters().at(specifier.index);
90
91
164M
    FormatParser argparser { specifier.flags };
92
164M
    TRY(parameter.visit([&]<typename T>(T const& value) {
93
164M
        if constexpr (IsSame<T, TypeErasedParameter::CustomType>) {
94
164M
            return value.formatter(params, builder, argparser, value.value);
95
164M
        } else {
96
164M
            return __format_value<T>(params, builder, argparser, &value);
97
164M
        }
98
164M
    }));
99
164M
    TRY(vformat_impl(params, builder, parser));
100
164M
    return {};
101
164M
}
102
103
} // namespace AK::{anonymous}
104
105
FormatParser::FormatParser(StringView input)
106
274M
    : GenericLexer(input)
107
274M
{
108
274M
}
109
StringView FormatParser::consume_literal()
110
274M
{
111
274M
    auto const begin = tell();
112
113
1.02G
    while (!is_eof()) {
114
919M
        if (consume_specific("{{"sv))
115
0
            continue;
116
117
919M
        if (consume_specific("}}"sv))
118
79.7k
            continue;
119
120
919M
        if (next_is(is_any_of("{}"sv)))
121
164M
            return m_input.substring_view(begin, tell() - begin);
122
123
755M
        consume();
124
755M
    }
125
126
110M
    return m_input.substring_view(begin);
127
274M
}
128
bool FormatParser::consume_number(size_t& value)
129
328M
{
130
328M
    value = 0;
131
132
328M
    bool consumed_at_least_one = false;
133
434M
    while (next_is(is_ascii_digit)) {
134
106M
        value *= 10;
135
106M
        value += parse_ascii_digit(consume());
136
106M
        consumed_at_least_one = true;
137
106M
    }
138
139
328M
    return consumed_at_least_one;
140
328M
}
141
bool FormatParser::consume_specifier(FormatSpecifier& specifier)
142
274M
{
143
274M
    VERIFY(!next_is('}'));
144
145
274M
    if (!consume_specific('{'))
146
110M
        return false;
147
148
164M
    if (!consume_number(specifier.index))
149
164M
        specifier.index = use_next_index;
150
151
164M
    if (consume_specific(':')) {
152
106M
        auto const begin = tell();
153
154
106M
        size_t level = 1;
155
530M
        while (level > 0) {
156
424M
            VERIFY(!is_eof());
157
158
424M
            if (consume_specific('{')) {
159
0
                ++level;
160
0
                continue;
161
0
            }
162
163
424M
            if (consume_specific('}')) {
164
106M
                --level;
165
106M
                continue;
166
106M
            }
167
168
318M
            consume();
169
318M
        }
170
171
106M
        specifier.flags = m_input.substring_view(begin, tell() - begin - 1);
172
106M
    } else {
173
58.0M
        if (!consume_specific('}'))
174
58.0M
            VERIFY_NOT_REACHED();
175
176
58.0M
        specifier.flags = ""sv;
177
58.0M
    }
178
179
164M
    return true;
180
164M
}
181
bool FormatParser::consume_replacement_field(size_t& index)
182
164M
{
183
164M
    if (!consume_specific('{'))
184
164M
        return false;
185
186
0
    if (!consume_number(index))
187
0
        index = use_next_index;
188
189
0
    if (!consume_specific('}'))
190
0
        VERIFY_NOT_REACHED();
191
192
0
    return true;
193
0
}
194
195
ErrorOr<void> FormatBuilder::put_padding(char fill, size_t amount)
196
164M
{
197
165M
    for (size_t i = 0; i < amount; ++i)
198
186k
        TRY(m_builder.try_append(fill));
199
164M
    return {};
200
164M
}
201
ErrorOr<void> FormatBuilder::put_literal(StringView value)
202
274M
{
203
1.03G
    for (size_t i = 0; i < value.length(); ++i) {
204
756M
        TRY(m_builder.try_append(value[i]));
205
756M
        if (value[i] == '{' || value[i] == '}')
206
79.7k
            ++i;
207
756M
    }
208
274M
    return {};
209
274M
}
210
211
ErrorOr<void> FormatBuilder::put_string(
212
    StringView value,
213
    Align align,
214
    size_t min_width,
215
    size_t max_width,
216
    char fill)
217
57.6M
{
218
57.6M
    auto const used_by_string = min(max_width, value.length());
219
57.6M
    auto const used_by_padding = max(min_width, used_by_string) - used_by_string;
220
221
57.6M
    if (used_by_string < value.length())
222
0
        value = value.substring_view(0, used_by_string);
223
224
57.6M
    if (align == Align::Left || align == Align::Default) {
225
57.6M
        TRY(m_builder.try_append(value));
226
57.6M
        TRY(put_padding(fill, used_by_padding));
227
57.6M
    } else if (align == Align::Center) {
228
0
        auto const used_by_left_padding = used_by_padding / 2;
229
0
        auto const used_by_right_padding = ceil_div<size_t, size_t>(used_by_padding, 2);
230
231
0
        TRY(put_padding(fill, used_by_left_padding));
232
0
        TRY(m_builder.try_append(value));
233
0
        TRY(put_padding(fill, used_by_right_padding));
234
0
    } else if (align == Align::Right) {
235
0
        TRY(put_padding(fill, used_by_padding));
236
0
        TRY(m_builder.try_append(value));
237
0
    }
238
57.6M
    return {};
239
57.6M
}
240
241
ErrorOr<void> FormatBuilder::put_u64(
242
    u64 value,
243
    u8 base,
244
    bool prefix,
245
    bool upper_case,
246
    bool zero_pad,
247
    bool use_separator,
248
    Align align,
249
    size_t min_width,
250
    char fill,
251
    SignMode sign_mode,
252
    bool is_negative)
253
107M
{
254
107M
    if (align == Align::Default)
255
107M
        align = Align::Right;
256
257
107M
    Array<u8, 128> buffer;
258
259
107M
    auto const used_by_digits = convert_unsigned_to_string(value, buffer, base, upper_case, use_separator);
260
261
107M
    size_t used_by_prefix = 0;
262
107M
    if (align == Align::Right && zero_pad) {
263
        // We want ByteString::formatted("{:#08x}", 32) to produce '0x00000020' instead of '0x000020'. This
264
        // behavior differs from both fmtlib and printf, but is more intuitive.
265
106M
        used_by_prefix = 0;
266
106M
    } else {
267
1.13M
        if (is_negative || sign_mode != SignMode::OnlyIfNeeded)
268
1.27k
            used_by_prefix += 1;
269
270
1.13M
        if (prefix) {
271
0
            if (base == 8)
272
0
                used_by_prefix += 1;
273
0
            else if (base == 16)
274
0
                used_by_prefix += 2;
275
0
            else if (base == 2)
276
0
                used_by_prefix += 2;
277
0
        }
278
1.13M
    }
279
280
107M
    auto const used_by_field = used_by_prefix + used_by_digits;
281
107M
    auto const used_by_padding = max(used_by_field, min_width) - used_by_field;
282
283
107M
    auto const put_prefix = [&]() -> ErrorOr<void> {
284
107M
        if (is_negative)
285
1.27k
            TRY(m_builder.try_append('-'));
286
107M
        else if (sign_mode == SignMode::Always)
287
0
            TRY(m_builder.try_append('+'));
288
107M
        else if (sign_mode == SignMode::Reserved)
289
0
            TRY(m_builder.try_append(' '));
290
291
107M
        if (prefix) {
292
0
            if (base == 2) {
293
0
                if (upper_case)
294
0
                    TRY(m_builder.try_append("0B"sv));
295
0
                else
296
0
                    TRY(m_builder.try_append("0b"sv));
297
0
            } else if (base == 8) {
298
0
                TRY(m_builder.try_append("0"sv));
299
0
            } else if (base == 16) {
300
0
                if (upper_case)
301
0
                    TRY(m_builder.try_append("0X"sv));
302
0
                else
303
0
                    TRY(m_builder.try_append("0x"sv));
304
0
            }
305
0
        }
306
107M
        return {};
307
107M
    };
308
309
107M
    auto const put_digits = [&]() -> ErrorOr<void> {
310
321M
        for (size_t i = 0; i < used_by_digits; ++i)
311
214M
            TRY(m_builder.try_append(buffer[i]));
312
107M
        return {};
313
107M
    };
314
315
107M
    if (align == Align::Left) {
316
0
        auto const used_by_right_padding = used_by_padding;
317
318
0
        TRY(put_prefix());
319
0
        TRY(put_digits());
320
0
        TRY(put_padding(fill, used_by_right_padding));
321
107M
    } else if (align == Align::Center) {
322
0
        auto const used_by_left_padding = used_by_padding / 2;
323
0
        auto const used_by_right_padding = ceil_div<size_t, size_t>(used_by_padding, 2);
324
325
0
        TRY(put_padding(fill, used_by_left_padding));
326
0
        TRY(put_prefix());
327
0
        TRY(put_digits());
328
0
        TRY(put_padding(fill, used_by_right_padding));
329
107M
    } else if (align == Align::Right) {
330
107M
        auto const used_by_left_padding = used_by_padding;
331
332
107M
        if (zero_pad) {
333
106M
            TRY(put_prefix());
334
106M
            TRY(put_padding('0', used_by_left_padding));
335
106M
            TRY(put_digits());
336
106M
        } else {
337
1.13M
            TRY(put_padding(fill, used_by_left_padding));
338
1.13M
            TRY(put_prefix());
339
1.13M
            TRY(put_digits());
340
1.13M
        }
341
107M
    }
342
107M
    return {};
343
107M
}
344
345
ErrorOr<void> FormatBuilder::put_i64(
346
    i64 value,
347
    u8 base,
348
    bool prefix,
349
    bool upper_case,
350
    bool zero_pad,
351
    bool use_separator,
352
    Align align,
353
    size_t min_width,
354
    char fill,
355
    SignMode sign_mode)
356
811k
{
357
811k
    auto const is_negative = value < 0;
358
811k
    u64 positive_value;
359
811k
    if (value == NumericLimits<i64>::min()) {
360
0
        positive_value = static_cast<u64>(NumericLimits<i64>::max()) + 1;
361
811k
    } else {
362
811k
        positive_value = is_negative ? -value : value;
363
811k
    }
364
365
811k
    TRY(put_u64(positive_value, base, prefix, upper_case, zero_pad, use_separator, align, min_width, fill, sign_mode, is_negative));
366
811k
    return {};
367
811k
}
368
369
ErrorOr<void> FormatBuilder::put_fixed_point(
370
    bool is_negative,
371
    i64 integer_value,
372
    u64 fraction_value,
373
    u64 fraction_one,
374
    size_t precision,
375
    u8 base,
376
    bool upper_case,
377
    bool zero_pad,
378
    bool use_separator,
379
    Align align,
380
    size_t min_width,
381
    size_t fraction_max_width,
382
    char fill,
383
    SignMode sign_mode)
384
0
{
385
0
    StringBuilder string_builder;
386
0
    FormatBuilder format_builder { string_builder };
387
388
0
    if (is_negative)
389
0
        integer_value = -integer_value;
390
391
0
    TRY(format_builder.put_u64(static_cast<u64>(integer_value), base, false, upper_case, false, use_separator, Align::Right, 0, ' ', sign_mode, is_negative));
392
393
0
    if (fraction_max_width && (zero_pad || fraction_value)) {
394
        // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
395
        // place to start would be the following video from CppCon 2019:
396
        // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
397
398
0
        if (is_negative && fraction_value)
399
0
            fraction_value = fraction_one - fraction_value;
400
401
0
        TRY(string_builder.try_append('.'));
402
403
0
        if (base == 10) {
404
0
            u64 scale = pow<u64>(5, precision);
405
            // FIXME: overflows (not before: fraction_value = (2^precision - 1) and precision >= 20) (use wider integer type)
406
0
            auto fraction = scale * fraction_value;
407
0
            TRY(format_builder.put_u64(fraction, base, false, upper_case, true, use_separator, Align::Right, precision));
408
0
        } else if (base == 16 || base == 8 || base == 2) {
409
0
            auto bits_per_character = log2(base);
410
0
            auto fraction = fraction_value << ((bits_per_character - (precision % bits_per_character)) % bits_per_character);
411
0
            TRY(format_builder.put_u64(fraction, base, false, upper_case, false, use_separator, Align::Right, precision / bits_per_character + (precision % bits_per_character != 0), '0'));
412
0
        } else {
413
0
            VERIFY_NOT_REACHED();
414
0
        }
415
0
    }
416
417
0
    auto formatted_string = string_builder.string_view();
418
0
    if (fraction_max_width && (zero_pad || fraction_value)) {
419
0
        auto point_index = formatted_string.find('.').value_or(0);
420
0
        if (!point_index)
421
0
            VERIFY_NOT_REACHED();
422
423
0
        if (auto formatted_length = (formatted_string.length() - point_index - 1); formatted_length > fraction_max_width) {
424
0
            formatted_string = formatted_string.substring_view(0, 1 + point_index + fraction_max_width);
425
0
        } else {
426
0
            string_builder.append_repeated('0', fraction_max_width - formatted_length);
427
0
            formatted_string = string_builder.string_view();
428
0
        }
429
430
0
        if (!zero_pad)
431
0
            formatted_string = formatted_string.trim("0"sv, TrimMode::Right);
432
433
0
        if (formatted_string.ends_with('.'))
434
0
            formatted_string = formatted_string.trim("."sv, TrimMode::Right);
435
0
    }
436
437
0
    TRY(put_string(formatted_string, align, min_width, NumericLimits<size_t>::max(), fill));
438
0
    return {};
439
0
}
440
441
#ifndef KERNEL
442
static ErrorOr<void> round_up_digits(StringBuilder& digits_builder)
443
0
{
444
0
    auto digits_buffer = TRY(digits_builder.to_byte_buffer());
445
0
    int current_position = digits_buffer.size() - 1;
446
447
0
    while (current_position >= 0) {
448
0
        if (digits_buffer[current_position] == '.') {
449
0
            --current_position;
450
0
            continue;
451
0
        }
452
0
        ++digits_buffer[current_position];
453
0
        if (digits_buffer[current_position] <= '9')
454
0
            break;
455
0
        digits_buffer[current_position] = '0';
456
0
        --current_position;
457
0
    }
458
459
0
    digits_builder.clear();
460
0
    if (current_position < 0)
461
0
        TRY(digits_builder.try_append('1'));
462
0
    return digits_builder.try_append(digits_buffer);
463
0
}
464
465
ErrorOr<void> FormatBuilder::put_f64_with_precision(
466
    double value,
467
    u8 base,
468
    bool upper_case,
469
    bool zero_pad,
470
    bool use_separator,
471
    Align align,
472
    size_t min_width,
473
    size_t precision,
474
    char fill,
475
    SignMode sign_mode,
476
    RealNumberDisplayMode display_mode)
477
0
{
478
0
    StringBuilder string_builder;
479
0
    FormatBuilder format_builder { string_builder };
480
481
0
    if (isnan(value) || isinf(value)) [[unlikely]] {
482
0
        if (value < 0.0)
483
0
            TRY(string_builder.try_append('-'));
484
0
        else if (sign_mode == SignMode::Always)
485
0
            TRY(string_builder.try_append('+'));
486
0
        else if (sign_mode == SignMode::Reserved)
487
0
            TRY(string_builder.try_append(' '));
488
489
0
        if (isnan(value))
490
0
            TRY(string_builder.try_append(upper_case ? "NAN"sv : "nan"sv));
491
0
        else
492
0
            TRY(string_builder.try_append(upper_case ? "INF"sv : "inf"sv));
493
0
        TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
494
0
        return {};
495
0
    }
496
497
0
    bool is_negative = value < 0.0;
498
0
    if (is_negative)
499
0
        value = -value;
500
501
0
    TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, false, use_separator, Align::Right, 0, ' ', sign_mode, is_negative));
502
0
    value -= static_cast<i64>(value);
503
504
0
    if (precision > 0) {
505
        // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
506
        // place to start would be the following video from CppCon 2019:
507
        // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
508
0
        double epsilon = 0.5;
509
0
        if (!zero_pad && display_mode != RealNumberDisplayMode::FixedPoint) {
510
0
            for (size_t i = 0; i < precision; ++i)
511
0
                epsilon /= 10.0;
512
0
        }
513
514
0
        for (size_t digit = 0; digit < precision; ++digit) {
515
0
            if (!zero_pad && display_mode != RealNumberDisplayMode::FixedPoint && value - static_cast<i64>(value) < epsilon)
516
0
                break;
517
518
0
            value *= 10.0;
519
0
            epsilon *= 10.0;
520
521
0
            if (value > NumericLimits<u32>::max())
522
0
                value -= static_cast<u64>(value) - (static_cast<u64>(value) % 10);
523
524
0
            if (digit == 0)
525
0
                TRY(string_builder.try_append('.'));
526
527
0
            TRY(string_builder.try_append('0' + (static_cast<u32>(value) % 10)));
528
0
        }
529
0
    }
530
531
    // Round up if the following decimal is 5 or higher
532
0
    if (static_cast<u64>(value * 10.0) % 10 >= 5)
533
0
        TRY(round_up_digits(string_builder));
534
535
0
    return put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill);
536
0
}
537
538
template<OneOf<f32, f64> T>
539
ErrorOr<void> FormatBuilder::put_f32_or_f64(
540
    T value,
541
    u8 base,
542
    bool upper_case,
543
    bool zero_pad,
544
    bool use_separator,
545
    Align align,
546
    size_t min_width,
547
    Optional<size_t> precision,
548
    char fill,
549
    SignMode sign_mode,
550
    RealNumberDisplayMode display_mode)
551
0
{
552
0
    if (precision.has_value() || base != 10)
553
0
        return put_f64_with_precision(value, base, upper_case, zero_pad, use_separator, align, min_width, precision.value_or(6), fill, sign_mode, display_mode);
554
555
    // No precision specified, so pick the best precision with roundtrip guarantees.
556
0
    StringBuilder builder;
557
558
    // Special cases: NaN, inf, -inf, 0 and -0.
559
0
    auto const is_nan = isnan(value);
560
0
    auto const is_inf = isinf(value);
561
0
    auto const is_zero = value == static_cast<T>(0.0) || value == static_cast<T>(-0.0);
562
0
    if (is_nan || is_inf || is_zero) {
563
0
        if (value < 0)
564
0
            TRY(builder.try_append('-'));
565
0
        else if (sign_mode == SignMode::Always)
566
0
            TRY(builder.try_append('+'));
567
0
        else if (sign_mode == SignMode::Reserved)
568
0
            TRY(builder.try_append(' '));
569
570
0
        if (is_nan)
571
0
            TRY(builder.try_append(upper_case ? "NAN"sv : "nan"sv));
572
0
        else if (is_inf)
573
0
            TRY(builder.try_append(upper_case ? "INF"sv : "inf"sv));
574
0
        else
575
0
            TRY(builder.try_append('0'));
576
577
0
        return put_string(builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill);
578
0
    }
579
580
0
    auto const [sign, mantissa, exponent] = convert_floating_point_to_decimal_exponential_form(value);
581
582
0
    auto convert_to_decimal_digits_array = [](auto x, auto& digits) -> size_t {
583
0
        size_t length = 0;
584
0
        for (; x; x /= 10)
585
0
            digits[length++] = x % 10 | '0';
586
0
        for (size_t i = 0; 2 * i + 1 < length; ++i)
587
0
            swap(digits[i], digits[length - i - 1]);
588
0
        return length;
589
0
    };
Unexecuted instantiation: _ZZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEfEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeEENKUlS7_RT0_E_clImNS_5ArrayIhLm20EEEEEmS7_SE_
Unexecuted instantiation: _ZZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEfEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeEENKUlS7_RT0_E_clIiNS_5ArrayIhLm5EEEEEmS7_SE_
Unexecuted instantiation: _ZZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEdEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeEENKUlS7_RT0_E_clImNS_5ArrayIhLm20EEEEEmS7_SE_
Unexecuted instantiation: _ZZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEdEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeEENKUlS7_RT0_E_clIiNS_5ArrayIhLm5EEEEEmS7_SE_
590
591
0
    Array<u8, 20> mantissa_digits;
592
0
    auto mantissa_length = convert_to_decimal_digits_array(mantissa, mantissa_digits);
593
594
0
    if (sign)
595
0
        TRY(builder.try_append('-'));
596
0
    else if (sign_mode == SignMode::Always)
597
0
        TRY(builder.try_append('+'));
598
0
    else if (sign_mode == SignMode::Reserved)
599
0
        TRY(builder.try_append(' '));
600
601
0
    auto const n = exponent + static_cast<i32>(mantissa_length);
602
0
    auto const mantissa_text = StringView { mantissa_digits.span().slice(0, mantissa_length) };
603
0
    size_t integral_part_end = 0;
604
    // NOTE: Range from ECMA262, seems like an okay default.
605
0
    if (n >= -5 && n <= 21) {
606
0
        if (exponent >= 0) {
607
0
            TRY(builder.try_append(mantissa_text));
608
0
            TRY(builder.try_append_repeated('0', exponent));
609
0
            integral_part_end = builder.length();
610
0
        } else if (n > 0) {
611
0
            TRY(builder.try_append(mantissa_text.substring_view(0, n)));
612
0
            integral_part_end = builder.length();
613
0
            TRY(builder.try_append('.'));
614
0
            TRY(builder.try_append(mantissa_text.substring_view(n)));
615
0
        } else {
616
0
            TRY(builder.try_append("0."sv));
617
0
            TRY(builder.try_append_repeated('0', -n));
618
0
            TRY(builder.try_append(mantissa_text));
619
0
            integral_part_end = 1;
620
0
        }
621
0
    } else {
622
0
        auto const exponent_sign = n < 0 ? '-' : '+';
623
0
        Array<u8, 5> exponent_digits;
624
0
        auto const exponent_length = convert_to_decimal_digits_array(abs(n - 1), exponent_digits);
625
0
        auto const exponent_text = StringView { exponent_digits.span().slice(0, exponent_length) };
626
0
        integral_part_end = 1;
627
628
0
        if (mantissa_length == 1) {
629
            // <mantissa>e<exponent>
630
0
            TRY(builder.try_append(mantissa_text));
631
0
            TRY(builder.try_append('e'));
632
0
            TRY(builder.try_append(exponent_sign));
633
0
            TRY(builder.try_append(exponent_text));
634
0
        } else {
635
            // <mantissa>.<mantissa[1..]>e<exponent>
636
0
            TRY(builder.try_append(mantissa_text.substring_view(0, 1)));
637
0
            TRY(builder.try_append('.'));
638
0
            TRY(builder.try_append(mantissa_text.substring_view(1)));
639
0
            TRY(builder.try_append('e'));
640
0
            TRY(builder.try_append(exponent_sign));
641
0
            TRY(builder.try_append(exponent_text));
642
0
        }
643
0
    }
644
645
0
    if (use_separator && integral_part_end > 3) {
646
        // Go backwards from the end of the integral part, inserting commas every 3 consecutive digits.
647
0
        StringBuilder separated_builder;
648
0
        auto const string_view = builder.string_view();
649
0
        for (size_t i = 0; i < integral_part_end; ++i) {
650
0
            auto const index_from_end = integral_part_end - i - 1;
651
0
            if (index_from_end > 0 && index_from_end != integral_part_end - 1 && index_from_end % 3 == 2)
652
0
                TRY(separated_builder.try_append(','));
653
0
            TRY(separated_builder.try_append(string_view[i]));
654
0
        }
655
0
        TRY(separated_builder.try_append(string_view.substring_view(integral_part_end)));
656
0
        builder = move(separated_builder);
657
0
    }
658
659
0
    return put_string(builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill);
660
0
}
Unexecuted instantiation: _ZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEfEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeE
Unexecuted instantiation: _ZN2AK13FormatBuilder14put_f32_or_f64ITkNS_8Concepts5OneOfIfdEEdEENS_7ErrorOrIvNS_5ErrorEEET_hbbbNS0_5AlignEmNS_8OptionalImEEcNS0_8SignModeENS0_21RealNumberDisplayModeE
661
662
ErrorOr<void> FormatBuilder::put_f80(
663
    long double value,
664
    u8 base,
665
    bool upper_case,
666
    bool use_separator,
667
    Align align,
668
    size_t min_width,
669
    size_t precision,
670
    char fill,
671
    SignMode sign_mode,
672
    RealNumberDisplayMode display_mode)
673
0
{
674
0
    StringBuilder string_builder;
675
0
    FormatBuilder format_builder { string_builder };
676
677
0
    if (isnan(value) || isinf(value)) [[unlikely]] {
678
0
        if (value < 0.0l)
679
0
            TRY(string_builder.try_append('-'));
680
0
        else if (sign_mode == SignMode::Always)
681
0
            TRY(string_builder.try_append('+'));
682
0
        else if (sign_mode == SignMode::Reserved)
683
0
            TRY(string_builder.try_append(' '));
684
685
0
        if (isnan(value))
686
0
            TRY(string_builder.try_append(upper_case ? "NAN"sv : "nan"sv));
687
0
        else
688
0
            TRY(string_builder.try_append(upper_case ? "INF"sv : "inf"sv));
689
0
        TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
690
0
        return {};
691
0
    }
692
693
0
    bool is_negative = value < 0.0l;
694
0
    if (is_negative)
695
0
        value = -value;
696
697
0
    TRY(format_builder.put_u64(static_cast<u64>(value), base, false, upper_case, false, use_separator, Align::Right, 0, ' ', sign_mode, is_negative));
698
0
    value -= static_cast<i64>(value);
699
700
0
    if (precision > 0) {
701
        // FIXME: This is a terrible approximation but doing it properly would be a lot of work. If someone is up for that, a good
702
        // place to start would be the following video from CppCon 2019:
703
        // https://youtu.be/4P_kbF0EbZM (Stephan T. Lavavej “Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss”)
704
0
        long double epsilon = 0.5l;
705
0
        if (display_mode != RealNumberDisplayMode::FixedPoint) {
706
0
            for (size_t i = 0; i < precision; ++i)
707
0
                epsilon /= 10.0l;
708
0
        }
709
710
0
        for (size_t digit = 0; digit < precision; ++digit) {
711
0
            if (display_mode != RealNumberDisplayMode::FixedPoint && value - static_cast<i64>(value) < epsilon)
712
0
                break;
713
714
0
            value *= 10.0l;
715
0
            epsilon *= 10.0l;
716
717
0
            if (value > NumericLimits<u32>::max())
718
0
                value -= static_cast<u64>(value) - (static_cast<u64>(value) % 10);
719
720
0
            if (digit == 0)
721
0
                TRY(string_builder.try_append('.'));
722
723
0
            TRY(string_builder.try_append('0' + (static_cast<u32>(value) % 10)));
724
0
        }
725
0
    }
726
727
    // Round up if the following decimal is 5 or higher
728
0
    if (static_cast<u64>(value * 10.0l) % 10 >= 5)
729
0
        TRY(round_up_digits(string_builder));
730
731
0
    TRY(put_string(string_builder.string_view(), align, min_width, NumericLimits<size_t>::max(), fill));
732
0
    return {};
733
0
}
734
735
#endif
736
737
ErrorOr<void> FormatBuilder::put_hexdump(ReadonlyBytes bytes, size_t width, char fill)
738
0
{
739
0
    auto put_char_view = [&](auto i) -> ErrorOr<void> {
740
0
        TRY(put_padding(fill, 4));
741
0
        for (size_t j = i - min(i, width); j < i; ++j) {
742
0
            auto ch = bytes[j];
743
0
            TRY(m_builder.try_append(ch >= 32 && ch <= 127 ? ch : '.')); // silly hack
744
0
        }
745
0
        return {};
746
0
    };
747
748
0
    for (size_t i = 0; i < bytes.size(); ++i) {
749
0
        if (width > 0) {
750
0
            if (i % width == 0 && i) {
751
0
                TRY(put_char_view(i));
752
0
                TRY(put_literal("\n"sv));
753
0
            }
754
0
        }
755
0
        TRY(put_u64(bytes[i], 16, false, false, true, false, Align::Right, 2));
756
0
    }
757
758
0
    if (width > 0)
759
0
        TRY(put_char_view(bytes.size()));
760
761
0
    return {};
762
0
}
763
764
ErrorOr<void> vformat(StringBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params)
765
110M
{
766
110M
    FormatBuilder fmtbuilder { builder };
767
110M
    FormatParser parser { fmtstr };
768
769
110M
    TRY(vformat_impl(params, fmtbuilder, parser));
770
110M
    return {};
771
110M
}
772
773
void StandardFormatter::parse(TypeErasedFormatParams& params, FormatParser& parser)
774
164M
{
775
164M
    if ("<^>"sv.contains(parser.peek(1))) {
776
0
        VERIFY(!parser.next_is(is_any_of("{}"sv)));
777
0
        m_fill = parser.consume();
778
0
    }
779
780
164M
    if (parser.consume_specific('<'))
781
0
        m_align = FormatBuilder::Align::Left;
782
164M
    else if (parser.consume_specific('^'))
783
0
        m_align = FormatBuilder::Align::Center;
784
164M
    else if (parser.consume_specific('>'))
785
0
        m_align = FormatBuilder::Align::Right;
786
787
164M
    if (parser.consume_specific('-'))
788
0
        m_sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
789
164M
    else if (parser.consume_specific('+'))
790
0
        m_sign_mode = FormatBuilder::SignMode::Always;
791
164M
    else if (parser.consume_specific(' '))
792
0
        m_sign_mode = FormatBuilder::SignMode::Reserved;
793
794
164M
    if (parser.consume_specific('#'))
795
0
        m_alternative_form = true;
796
797
164M
    if (parser.consume_specific('\''))
798
0
        m_use_separator = true;
799
800
164M
    if (parser.consume_specific('0'))
801
106M
        m_zero_pad = true;
802
803
164M
    if (size_t index = 0; parser.consume_replacement_field(index)) {
804
0
        if (index == use_next_index)
805
0
            index = params.take_next_index();
806
807
0
        m_width = params.parameters().at(index).to_size();
808
164M
    } else if (size_t width = 0; parser.consume_number(width)) {
809
106M
        m_width = width;
810
106M
    }
811
812
164M
    if (parser.consume_specific('.')) {
813
0
        if (size_t index = 0; parser.consume_replacement_field(index)) {
814
0
            if (index == use_next_index)
815
0
                index = params.take_next_index();
816
817
0
            m_precision = params.parameters().at(index).to_size();
818
0
        } else if (size_t precision = 0; parser.consume_number(precision)) {
819
0
            m_precision = precision;
820
0
        }
821
0
    }
822
823
164M
    if (parser.consume_specific('b'))
824
0
        m_mode = Mode::Binary;
825
164M
    else if (parser.consume_specific('B'))
826
0
        m_mode = Mode::BinaryUppercase;
827
164M
    else if (parser.consume_specific('d'))
828
0
        m_mode = Mode::Decimal;
829
164M
    else if (parser.consume_specific('o'))
830
0
        m_mode = Mode::Octal;
831
164M
    else if (parser.consume_specific('x'))
832
44
        m_mode = Mode::Hexadecimal;
833
164M
    else if (parser.consume_specific('X'))
834
106M
        m_mode = Mode::HexadecimalUppercase;
835
58.0M
    else if (parser.consume_specific('c'))
836
0
        m_mode = Mode::Character;
837
58.0M
    else if (parser.consume_specific('s'))
838
0
        m_mode = Mode::String;
839
58.0M
    else if (parser.consume_specific('p'))
840
0
        m_mode = Mode::Pointer;
841
58.0M
    else if (parser.consume_specific('f'))
842
0
        m_mode = Mode::FixedPoint;
843
58.0M
    else if (parser.consume_specific('a'))
844
0
        m_mode = Mode::Hexfloat;
845
58.0M
    else if (parser.consume_specific('A'))
846
0
        m_mode = Mode::HexfloatUppercase;
847
58.0M
    else if (parser.consume_specific("hex-dump"sv))
848
0
        m_mode = Mode::HexDump;
849
850
164M
    if (!parser.is_eof())
851
0
        dbgln("{} did not consume '{}'", __PRETTY_FUNCTION__, parser.remaining());
852
853
164M
    VERIFY(parser.is_eof());
854
164M
}
855
856
ErrorOr<void> Formatter<StringView>::format(FormatBuilder& builder, StringView value)
857
57.6M
{
858
57.6M
    if (m_sign_mode != FormatBuilder::SignMode::Default)
859
57.6M
        VERIFY_NOT_REACHED();
860
57.6M
    if (m_zero_pad)
861
57.6M
        VERIFY_NOT_REACHED();
862
57.6M
    if (m_mode != Mode::Default && m_mode != Mode::String && m_mode != Mode::Character && m_mode != Mode::HexDump)
863
57.6M
        VERIFY_NOT_REACHED();
864
865
57.6M
    m_width = m_width.value_or(0);
866
57.6M
    m_precision = m_precision.value_or(NumericLimits<size_t>::max());
867
868
57.6M
    if (m_mode == Mode::HexDump)
869
0
        return builder.put_hexdump(value.bytes(), m_width.value(), m_fill);
870
57.6M
    return builder.put_string(value, m_align, m_width.value(), m_precision.value(), m_fill);
871
57.6M
}
872
873
ErrorOr<void> Formatter<FormatString>::vformat(FormatBuilder& builder, StringView fmtstr, TypeErasedFormatParams& params)
874
141k
{
875
141k
    StringBuilder string_builder;
876
141k
    TRY(AK::vformat(string_builder, fmtstr, params));
877
141k
    TRY(Formatter<StringView>::format(builder, string_builder.string_view()));
878
141k
    return {};
879
141k
}
880
881
template<Integral T>
882
ErrorOr<void> Formatter<T>::format(FormatBuilder& builder, T value)
883
107M
{
884
107M
    if (m_mode == Mode::Character) {
885
0
        m_mode = Mode::String;
886
887
0
        Formatter<StringView> formatter { *this };
888
889
        // FIXME: We just support ASCII for now, in the future maybe unicode?
890
0
        VERIFY(value >= 0 && value <= 127);
891
892
        // Convert value to a single byte. This is important for big-endian systems, because the LSB is stored in the last byte.
893
0
        char const c = (value & 0x7f);
894
895
0
        return formatter.format(builder, StringView { &c, 1 });
896
0
    }
897
898
107M
    if (m_precision.has_value())
899
107M
        VERIFY_NOT_REACHED();
900
901
107M
    if (m_mode == Mode::Pointer) {
902
0
        if (m_sign_mode != FormatBuilder::SignMode::Default)
903
0
            VERIFY_NOT_REACHED();
904
0
        if (m_align != FormatBuilder::Align::Default)
905
0
            VERIFY_NOT_REACHED();
906
0
        if (m_alternative_form)
907
0
            VERIFY_NOT_REACHED();
908
0
        if (m_width.has_value())
909
0
            VERIFY_NOT_REACHED();
910
911
0
        m_mode = Mode::Hexadecimal;
912
0
        m_alternative_form = true;
913
0
        m_width = 2 * sizeof(void*);
914
0
        m_zero_pad = true;
915
0
    }
916
917
107M
    u8 base = 0;
918
107M
    bool upper_case = false;
919
107M
    if (m_mode == Mode::Binary) {
920
0
        base = 2;
921
107M
    } else if (m_mode == Mode::BinaryUppercase) {
922
0
        base = 2;
923
0
        upper_case = true;
924
107M
    } else if (m_mode == Mode::Octal) {
925
0
        base = 8;
926
107M
    } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) {
927
1.13M
        base = 10;
928
106M
    } else if (m_mode == Mode::Hexadecimal) {
929
44
        base = 16;
930
106M
    } else if (m_mode == Mode::HexadecimalUppercase) {
931
106M
        base = 16;
932
106M
        upper_case = true;
933
106M
    } else if (m_mode == Mode::HexDump) {
934
0
        m_width = m_width.value_or(32);
935
0
        return builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
936
0
    } else {
937
0
        VERIFY_NOT_REACHED();
938
0
    }
939
940
107M
    m_width = m_width.value_or(0);
941
942
    if constexpr (IsSame<MakeUnsigned<T>, T>)
943
106M
        return builder.put_u64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
944
    else
945
811k
        return builder.put_i64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
946
107M
}
Unexecuted instantiation: AK::Formatter<unsigned char, void>::format(AK::FormatBuilder&, unsigned char)
Unexecuted instantiation: AK::Formatter<unsigned short, void>::format(AK::FormatBuilder&, unsigned short)
Unexecuted instantiation: AK::Formatter<unsigned int, void>::format(AK::FormatBuilder&, unsigned int)
AK::Formatter<unsigned long, void>::format(AK::FormatBuilder&, unsigned long)
Line
Count
Source
883
106M
{
884
106M
    if (m_mode == Mode::Character) {
885
0
        m_mode = Mode::String;
886
887
0
        Formatter<StringView> formatter { *this };
888
889
        // FIXME: We just support ASCII for now, in the future maybe unicode?
890
0
        VERIFY(value >= 0 && value <= 127);
891
892
        // Convert value to a single byte. This is important for big-endian systems, because the LSB is stored in the last byte.
893
0
        char const c = (value & 0x7f);
894
895
0
        return formatter.format(builder, StringView { &c, 1 });
896
0
    }
897
898
106M
    if (m_precision.has_value())
899
106M
        VERIFY_NOT_REACHED();
900
901
106M
    if (m_mode == Mode::Pointer) {
902
0
        if (m_sign_mode != FormatBuilder::SignMode::Default)
903
0
            VERIFY_NOT_REACHED();
904
0
        if (m_align != FormatBuilder::Align::Default)
905
0
            VERIFY_NOT_REACHED();
906
0
        if (m_alternative_form)
907
0
            VERIFY_NOT_REACHED();
908
0
        if (m_width.has_value())
909
0
            VERIFY_NOT_REACHED();
910
911
0
        m_mode = Mode::Hexadecimal;
912
0
        m_alternative_form = true;
913
0
        m_width = 2 * sizeof(void*);
914
0
        m_zero_pad = true;
915
0
    }
916
917
106M
    u8 base = 0;
918
106M
    bool upper_case = false;
919
106M
    if (m_mode == Mode::Binary) {
920
0
        base = 2;
921
106M
    } else if (m_mode == Mode::BinaryUppercase) {
922
0
        base = 2;
923
0
        upper_case = true;
924
106M
    } else if (m_mode == Mode::Octal) {
925
0
        base = 8;
926
106M
    } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) {
927
323k
        base = 10;
928
106M
    } else if (m_mode == Mode::Hexadecimal) {
929
44
        base = 16;
930
106M
    } else if (m_mode == Mode::HexadecimalUppercase) {
931
106M
        base = 16;
932
106M
        upper_case = true;
933
106M
    } else if (m_mode == Mode::HexDump) {
934
0
        m_width = m_width.value_or(32);
935
0
        return builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
936
0
    } else {
937
0
        VERIFY_NOT_REACHED();
938
0
    }
939
940
106M
    m_width = m_width.value_or(0);
941
942
    if constexpr (IsSame<MakeUnsigned<T>, T>)
943
106M
        return builder.put_u64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
944
    else
945
        return builder.put_i64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
946
106M
}
Unexecuted instantiation: AK::Formatter<unsigned long long, void>::format(AK::FormatBuilder&, unsigned long long)
Unexecuted instantiation: AK::Formatter<short, void>::format(AK::FormatBuilder&, short)
AK::Formatter<int, void>::format(AK::FormatBuilder&, int)
Line
Count
Source
883
742k
{
884
742k
    if (m_mode == Mode::Character) {
885
0
        m_mode = Mode::String;
886
887
0
        Formatter<StringView> formatter { *this };
888
889
        // FIXME: We just support ASCII for now, in the future maybe unicode?
890
0
        VERIFY(value >= 0 && value <= 127);
891
892
        // Convert value to a single byte. This is important for big-endian systems, because the LSB is stored in the last byte.
893
0
        char const c = (value & 0x7f);
894
895
0
        return formatter.format(builder, StringView { &c, 1 });
896
0
    }
897
898
742k
    if (m_precision.has_value())
899
742k
        VERIFY_NOT_REACHED();
900
901
742k
    if (m_mode == Mode::Pointer) {
902
0
        if (m_sign_mode != FormatBuilder::SignMode::Default)
903
0
            VERIFY_NOT_REACHED();
904
0
        if (m_align != FormatBuilder::Align::Default)
905
0
            VERIFY_NOT_REACHED();
906
0
        if (m_alternative_form)
907
0
            VERIFY_NOT_REACHED();
908
0
        if (m_width.has_value())
909
0
            VERIFY_NOT_REACHED();
910
911
0
        m_mode = Mode::Hexadecimal;
912
0
        m_alternative_form = true;
913
0
        m_width = 2 * sizeof(void*);
914
0
        m_zero_pad = true;
915
0
    }
916
917
742k
    u8 base = 0;
918
742k
    bool upper_case = false;
919
742k
    if (m_mode == Mode::Binary) {
920
0
        base = 2;
921
742k
    } else if (m_mode == Mode::BinaryUppercase) {
922
0
        base = 2;
923
0
        upper_case = true;
924
742k
    } else if (m_mode == Mode::Octal) {
925
0
        base = 8;
926
742k
    } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) {
927
742k
        base = 10;
928
742k
    } else if (m_mode == Mode::Hexadecimal) {
929
0
        base = 16;
930
0
    } else if (m_mode == Mode::HexadecimalUppercase) {
931
0
        base = 16;
932
0
        upper_case = true;
933
0
    } else if (m_mode == Mode::HexDump) {
934
0
        m_width = m_width.value_or(32);
935
0
        return builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
936
0
    } else {
937
0
        VERIFY_NOT_REACHED();
938
0
    }
939
940
742k
    m_width = m_width.value_or(0);
941
942
    if constexpr (IsSame<MakeUnsigned<T>, T>)
943
        return builder.put_u64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
944
    else
945
742k
        return builder.put_i64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
946
742k
}
AK::Formatter<long, void>::format(AK::FormatBuilder&, long)
Line
Count
Source
883
68.9k
{
884
68.9k
    if (m_mode == Mode::Character) {
885
0
        m_mode = Mode::String;
886
887
0
        Formatter<StringView> formatter { *this };
888
889
        // FIXME: We just support ASCII for now, in the future maybe unicode?
890
0
        VERIFY(value >= 0 && value <= 127);
891
892
        // Convert value to a single byte. This is important for big-endian systems, because the LSB is stored in the last byte.
893
0
        char const c = (value & 0x7f);
894
895
0
        return formatter.format(builder, StringView { &c, 1 });
896
0
    }
897
898
68.9k
    if (m_precision.has_value())
899
68.9k
        VERIFY_NOT_REACHED();
900
901
68.9k
    if (m_mode == Mode::Pointer) {
902
0
        if (m_sign_mode != FormatBuilder::SignMode::Default)
903
0
            VERIFY_NOT_REACHED();
904
0
        if (m_align != FormatBuilder::Align::Default)
905
0
            VERIFY_NOT_REACHED();
906
0
        if (m_alternative_form)
907
0
            VERIFY_NOT_REACHED();
908
0
        if (m_width.has_value())
909
0
            VERIFY_NOT_REACHED();
910
911
0
        m_mode = Mode::Hexadecimal;
912
0
        m_alternative_form = true;
913
0
        m_width = 2 * sizeof(void*);
914
0
        m_zero_pad = true;
915
0
    }
916
917
68.9k
    u8 base = 0;
918
68.9k
    bool upper_case = false;
919
68.9k
    if (m_mode == Mode::Binary) {
920
0
        base = 2;
921
68.9k
    } else if (m_mode == Mode::BinaryUppercase) {
922
0
        base = 2;
923
0
        upper_case = true;
924
68.9k
    } else if (m_mode == Mode::Octal) {
925
0
        base = 8;
926
68.9k
    } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) {
927
68.9k
        base = 10;
928
68.9k
    } else if (m_mode == Mode::Hexadecimal) {
929
0
        base = 16;
930
0
    } else if (m_mode == Mode::HexadecimalUppercase) {
931
0
        base = 16;
932
0
        upper_case = true;
933
0
    } else if (m_mode == Mode::HexDump) {
934
0
        m_width = m_width.value_or(32);
935
0
        return builder.put_hexdump({ &value, sizeof(value) }, m_width.value(), m_fill);
936
0
    } else {
937
0
        VERIFY_NOT_REACHED();
938
0
    }
939
940
68.9k
    m_width = m_width.value_or(0);
941
942
    if constexpr (IsSame<MakeUnsigned<T>, T>)
943
        return builder.put_u64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
944
    else
945
68.9k
        return builder.put_i64(value, base, m_alternative_form, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_fill, m_sign_mode);
946
68.9k
}
Unexecuted instantiation: AK::Formatter<long long, void>::format(AK::FormatBuilder&, long long)
Unexecuted instantiation: AK::Formatter<signed char, void>::format(AK::FormatBuilder&, signed char)
947
948
ErrorOr<void> Formatter<char>::format(FormatBuilder& builder, char value)
949
0
{
950
0
    if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
951
        // Trick: signed char != char. (Sometimes weird features are actually helpful.)
952
0
        if constexpr (IsSigned<char>) {
953
0
            Formatter<signed char> formatter { *this };
954
0
            return formatter.format(builder, static_cast<signed char>(value));
955
        } else {
956
            Formatter<unsigned char> formatter { *this };
957
            return formatter.format(builder, static_cast<unsigned char>(value));
958
        }
959
0
    } else {
960
0
        Formatter<StringView> formatter { *this };
961
0
        return formatter.format(builder, { &value, 1 });
962
0
    }
963
0
}
964
ErrorOr<void> Formatter<wchar_t>::format(FormatBuilder& builder, wchar_t value)
965
0
{
966
0
    if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
967
0
        Formatter<u32> formatter { *this };
968
0
        return formatter.format(builder, static_cast<u32>(value));
969
0
    } else {
970
0
        StringBuilder codepoint;
971
0
        codepoint.append_code_point(value);
972
973
0
        Formatter<StringView> formatter { *this };
974
0
        return formatter.format(builder, codepoint.string_view());
975
0
    }
976
0
}
977
ErrorOr<void> Formatter<bool>::format(FormatBuilder& builder, bool value)
978
0
{
979
0
    if (m_mode == Mode::Binary || m_mode == Mode::BinaryUppercase || m_mode == Mode::Decimal || m_mode == Mode::Octal || m_mode == Mode::Hexadecimal || m_mode == Mode::HexadecimalUppercase) {
980
0
        Formatter<u8> formatter { *this };
981
0
        return formatter.format(builder, static_cast<u8>(value));
982
0
    } else if (m_mode == Mode::HexDump) {
983
0
        return builder.put_hexdump({ &value, sizeof(value) }, m_width.value_or(32), m_fill);
984
0
    } else {
985
0
        Formatter<StringView> formatter { *this };
986
0
        return formatter.format(builder, value ? "true"sv : "false"sv);
987
0
    }
988
0
}
989
#ifndef KERNEL
990
ErrorOr<void> Formatter<long double>::format(FormatBuilder& builder, long double value)
991
0
{
992
0
    u8 base;
993
0
    bool upper_case;
994
0
    FormatBuilder::RealNumberDisplayMode real_number_display_mode = FormatBuilder::RealNumberDisplayMode::General;
995
0
    if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
996
0
        base = 10;
997
0
        upper_case = false;
998
0
        if (m_mode == Mode::FixedPoint)
999
0
            real_number_display_mode = FormatBuilder::RealNumberDisplayMode::FixedPoint;
1000
0
    } else if (m_mode == Mode::Hexfloat) {
1001
0
        base = 16;
1002
0
        upper_case = false;
1003
0
    } else if (m_mode == Mode::HexfloatUppercase) {
1004
0
        base = 16;
1005
0
        upper_case = true;
1006
0
    } else {
1007
0
        VERIFY_NOT_REACHED();
1008
0
    }
1009
1010
0
    m_width = m_width.value_or(0);
1011
0
    m_precision = m_precision.value_or(6);
1012
1013
0
    return builder.put_f80(value, base, upper_case, m_use_separator, m_align, m_width.value(), m_precision.value(), m_fill, m_sign_mode, real_number_display_mode);
1014
0
}
1015
1016
ErrorOr<void> Formatter<double>::format(FormatBuilder& builder, double value)
1017
0
{
1018
0
    u8 base;
1019
0
    bool upper_case;
1020
0
    FormatBuilder::RealNumberDisplayMode real_number_display_mode = FormatBuilder::RealNumberDisplayMode::General;
1021
0
    if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
1022
0
        base = 10;
1023
0
        upper_case = false;
1024
0
        if (m_mode == Mode::FixedPoint)
1025
0
            real_number_display_mode = FormatBuilder::RealNumberDisplayMode::FixedPoint;
1026
0
    } else if (m_mode == Mode::Hexfloat) {
1027
0
        base = 16;
1028
0
        upper_case = false;
1029
0
    } else if (m_mode == Mode::HexfloatUppercase) {
1030
0
        base = 16;
1031
0
        upper_case = true;
1032
0
    } else {
1033
0
        VERIFY_NOT_REACHED();
1034
0
    }
1035
1036
0
    m_width = m_width.value_or(0);
1037
1038
0
    return builder.put_f32_or_f64(value, base, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_precision, m_fill, m_sign_mode, real_number_display_mode);
1039
0
}
1040
1041
ErrorOr<void> Formatter<float>::format(FormatBuilder& builder, float value)
1042
0
{
1043
0
    u8 base;
1044
0
    bool upper_case;
1045
0
    FormatBuilder::RealNumberDisplayMode real_number_display_mode = FormatBuilder::RealNumberDisplayMode::General;
1046
0
    if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
1047
0
        base = 10;
1048
0
        upper_case = false;
1049
0
        if (m_mode == Mode::FixedPoint)
1050
0
            real_number_display_mode = FormatBuilder::RealNumberDisplayMode::FixedPoint;
1051
0
    } else if (m_mode == Mode::Hexfloat) {
1052
0
        base = 16;
1053
0
        upper_case = false;
1054
0
    } else if (m_mode == Mode::HexfloatUppercase) {
1055
0
        base = 16;
1056
0
        upper_case = true;
1057
0
    } else {
1058
0
        VERIFY_NOT_REACHED();
1059
0
    }
1060
1061
0
    m_width = m_width.value_or(0);
1062
1063
0
    return builder.put_f32_or_f64(value, base, upper_case, m_zero_pad, m_use_separator, m_align, m_width.value(), m_precision, m_fill, m_sign_mode, real_number_display_mode);
1064
0
}
1065
1066
template ErrorOr<void> FormatBuilder::put_f32_or_f64<float>(float, u8, bool, bool, bool, Align, size_t, Optional<size_t>, char, SignMode, RealNumberDisplayMode);
1067
template ErrorOr<void> FormatBuilder::put_f32_or_f64<double>(double, u8, bool, bool, bool, Align, size_t, Optional<size_t>, char, SignMode, RealNumberDisplayMode);
1068
#endif
1069
1070
#ifndef KERNEL
1071
void vout(FILE* file, StringView fmtstr, TypeErasedFormatParams& params, bool newline)
1072
222
{
1073
222
    StringBuilder builder;
1074
222
    MUST(vformat(builder, fmtstr, params));
1075
1076
222
    if (newline)
1077
222
        builder.append('\n');
1078
1079
222
    auto const string = builder.string_view();
1080
222
    auto const retval = ::fwrite(string.characters_without_null_termination(), 1, string.length(), file);
1081
222
    if (static_cast<size_t>(retval) != string.length()) {
1082
0
        auto error = ferror(file);
1083
0
        dbgln("vout() failed ({} written out of {}), error was {} ({})", retval, string.length(), error, strerror(error));
1084
0
    }
1085
222
}
1086
#endif
1087
1088
#ifndef KERNEL
1089
// FIXME: Deduplicate with Core::Process:get_name()
1090
[[gnu::used]] static ByteString process_name_helper()
1091
0
{
1092
#    if defined(AK_OS_SERENITY)
1093
    char buffer[BUFSIZ] = {};
1094
    int rc = get_process_name(buffer, BUFSIZ);
1095
    if (rc != 0)
1096
        return ByteString {};
1097
    return StringView { buffer, strlen(buffer) };
1098
#    elif defined(AK_LIBC_GLIBC) || defined(AK_OS_LINUX)
1099
    return StringView { program_invocation_name, strlen(program_invocation_name) };
1100
#    elif defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU)
1101
    auto const* progname = getprogname();
1102
    return StringView { progname, strlen(progname) };
1103
#    else
1104
    // FIXME: Implement process_name_helper() for other platforms.
1105
    return StringView {};
1106
#    endif
1107
0
}
1108
1109
static StringView process_name_for_logging()
1110
0
{
1111
    // NOTE: We use AK::Format in the DynamicLoader and LibC, which cannot use thread-safe statics
1112
    // Also go to extraordinary lengths here to avoid strlen() on the process name every call to dbgln
1113
0
    static char process_name_buf[256] = {};
1114
0
    static StringView process_name;
1115
0
    static bool process_name_retrieved = false;
1116
0
    if (!process_name_retrieved) {
1117
0
        auto path = LexicalPath(process_name_helper());
1118
0
        process_name_retrieved = true;
1119
0
        (void)path.basename().copy_characters_to_buffer(process_name_buf, sizeof(process_name_buf));
1120
0
        process_name = { process_name_buf, strlen(process_name_buf) };
1121
0
    }
1122
0
    return process_name;
1123
0
}
1124
#endif
1125
1126
static bool is_debug_enabled = true;
1127
1128
void set_debug_enabled(bool value)
1129
131k
{
1130
131k
    is_debug_enabled = value;
1131
131k
}
1132
1133
// On Serenity, dbgln goes to a non-stderr output
1134
static bool is_rich_debug_enabled =
1135
#if defined(AK_OS_SERENITY)
1136
    true;
1137
#else
1138
    false;
1139
#endif
1140
1141
void set_rich_debug_enabled(bool value)
1142
0
{
1143
0
    is_rich_debug_enabled = value;
1144
0
}
1145
1146
void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
1147
14.9M
{
1148
14.9M
    if (!is_debug_enabled)
1149
14.9M
        return;
1150
1151
0
    StringBuilder builder;
1152
1153
0
    if (is_rich_debug_enabled) {
1154
#if defined(PREKERNEL)
1155
        ;
1156
#elif defined(KERNEL)
1157
        if (Kernel::Processor::is_initialized() && TimeManagement::is_initialized()) {
1158
            auto time = TimeManagement::the().monotonic_time(TimePrecision::Coarse);
1159
            if (Kernel::Thread::current()) {
1160
                auto& thread = *Kernel::Thread::current();
1161
                thread.process().name().with([&](auto& process_name) {
1162
                    builder.appendff("{}.{:03} \033[34;1m[#{} {}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id(), process_name.representable_view(), thread.pid().value(), thread.tid().value());
1163
                });
1164
            } else {
1165
                builder.appendff("{}.{:03} \033[34;1m[#{} Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, Kernel::Processor::current_id());
1166
            }
1167
        } else {
1168
            builder.appendff("\033[34;1m[Kernel]\033[0m: ");
1169
        }
1170
#elif !defined(AK_OS_WINDOWS)
1171
        auto process_name = process_name_for_logging();
1172
0
        if (!process_name.is_empty()) {
1173
0
            struct timespec ts = {};
1174
0
            clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
1175
0
            auto pid = getpid();
1176
0
#    if defined(AK_OS_SERENITY) || defined(AK_OS_LINUX)
1177
            // Linux and Serenity handle thread IDs as if they are related to process ids
1178
0
            auto tid = gettid();
1179
0
            if (pid == tid)
1180
0
#    endif
1181
0
            {
1182
0
                builder.appendff("{}.{:03} \033[33;1m{}({})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name, pid);
1183
0
            }
1184
0
#    if defined(AK_OS_SERENITY) || defined(AK_OS_LINUX)
1185
0
            else {
1186
0
                builder.appendff("{}.{:03} \033[33;1m{}({}:{})\033[0m: ", ts.tv_sec, ts.tv_nsec / 1000000, process_name, pid, tid);
1187
0
            }
1188
0
#    endif
1189
0
        }
1190
0
#endif
1191
0
    }
1192
1193
0
    MUST(vformat(builder, fmtstr, params));
1194
0
    if (newline)
1195
0
        builder.append('\n');
1196
0
    auto const string = builder.string_view();
1197
1198
#ifdef AK_OS_SERENITY
1199
#    if defined(KERNEL) && !defined(PREKERNEL)
1200
    if (!Kernel::Processor::is_initialized()) {
1201
        kernelearlyputstr(string.characters_without_null_termination(), string.length());
1202
        return;
1203
    }
1204
#    endif
1205
#endif
1206
0
    dbgputstr(string.characters_without_null_termination(), string.length());
1207
0
}
1208
1209
#if defined(KERNEL) && !defined(PREKERNEL)
1210
void vdmesgln(StringView fmtstr, TypeErasedFormatParams& params)
1211
{
1212
    StringBuilder builder;
1213
1214
#    ifdef AK_OS_SERENITY
1215
    if (TimeManagement::is_initialized()) {
1216
        auto time = TimeManagement::the().monotonic_time(TimePrecision::Coarse);
1217
1218
        if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
1219
            auto& thread = *Kernel::Thread::current();
1220
            thread.process().name().with([&](auto& process_name) {
1221
                builder.appendff("{}.{:03} \033[34;1m[{}({}:{})]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000, process_name.representable_view(), thread.pid().value(), thread.tid().value());
1222
            });
1223
        } else {
1224
            builder.appendff("{}.{:03} \033[34;1m[Kernel]\033[0m: ", time.truncated_seconds(), time.nanoseconds_within_second() / 1000000);
1225
        }
1226
    } else {
1227
        builder.appendff("\033[34;1m[Kernel]\033[0m: ");
1228
    }
1229
#    endif
1230
1231
    MUST(vformat(builder, fmtstr, params));
1232
    builder.append('\n');
1233
1234
    auto const string = builder.string_view();
1235
    kernelputstr(string.characters_without_null_termination(), string.length());
1236
}
1237
1238
void v_critical_dmesgln(StringView fmtstr, TypeErasedFormatParams& params)
1239
{
1240
    // FIXME: Try to avoid memory allocations further to prevent faulting
1241
    // at OOM conditions.
1242
1243
    StringBuilder builder;
1244
#    ifdef AK_OS_SERENITY
1245
    if (Kernel::Processor::is_initialized() && Kernel::Thread::current()) {
1246
        auto& thread = *Kernel::Thread::current();
1247
        thread.process().name().with([&](auto& process_name) {
1248
            builder.appendff("[{}({}:{})]: ", process_name.representable_view(), thread.pid().value(), thread.tid().value());
1249
        });
1250
    } else {
1251
        builder.appendff("[Kernel]: ");
1252
    }
1253
#    endif
1254
1255
    MUST(vformat(builder, fmtstr, params));
1256
    builder.append('\n');
1257
1258
    auto const string = builder.string_view();
1259
    kernelcriticalputstr(string.characters_without_null_termination(), string.length());
1260
}
1261
1262
#endif
1263
1264
template struct Formatter<unsigned char, void>;
1265
template struct Formatter<unsigned short, void>;
1266
template struct Formatter<unsigned int, void>;
1267
template struct Formatter<unsigned long, void>;
1268
template struct Formatter<unsigned long long, void>;
1269
template struct Formatter<short, void>;
1270
template struct Formatter<int, void>;
1271
template struct Formatter<long, void>;
1272
template struct Formatter<long long, void>;
1273
template struct Formatter<signed char, void>;
1274
1275
} // namespace AK