diff options
author | Tom <tomut@yahoo.com> | 2021-12-27 18:23:04 -0700 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-01-23 22:45:21 +0000 |
commit | f021baf25507e466def8b07ca48a7b54bf140131 (patch) | |
tree | cba010a968e97cf097f5d00247fd620660638394 /AK/Format.h | |
parent | 77b3230c806d3ee8d5ceb50b60a1ed88ba62d737 (diff) | |
download | serenity-f021baf25507e466def8b07ca48a7b54bf140131.zip |
AK: Add Formatter<FixedPoint<...>> without floating point
Rather than casting the FixedPoint to double, format the FixedPoint
directly. This avoids using floating point instruction, which in
turn enables this to be used even in the kernel.
Diffstat (limited to 'AK/Format.h')
-rw-r--r-- | AK/Format.h | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/AK/Format.h b/AK/Format.h index 3d4f33bc6a..d5e127356f 100644 --- a/AK/Format.h +++ b/AK/Format.h @@ -12,6 +12,7 @@ #include <AK/AnyOf.h> #include <AK/Array.h> #include <AK/Error.h> +#include <AK/FixedPoint.h> #include <AK/Forward.h> #include <AK/Optional.h> #include <AK/StringView.h> @@ -185,6 +186,19 @@ public: char fill = ' ', SignMode sign_mode = SignMode::OnlyIfNeeded); + ErrorOr<void> put_fixed_point( + i64 integer_value, + u64 fraction_value, + u64 fraction_one, + u8 base = 10, + bool upper_case = false, + bool zero_pad = false, + Align align = Align::Right, + size_t min_width = 0, + size_t precision = 6, + char fill = ' ', + SignMode sign_mode = SignMode::OnlyIfNeeded); + #ifndef KERNEL ErrorOr<void> put_f80( long double value, @@ -469,6 +483,41 @@ struct Formatter<long double> : StandardFormatter { }; #endif +template<size_t precision, typename Underlying> +struct Formatter<FixedPoint<precision, Underlying>> : StandardFormatter { + Formatter() = default; + explicit Formatter(StandardFormatter formatter) + : StandardFormatter(formatter) + { + } + + ErrorOr<void> format(FormatBuilder& builder, FixedPoint<precision, Underlying> value) + { + u8 base; + bool upper_case; + if (m_mode == Mode::Default || m_mode == Mode::Float) { + base = 10; + upper_case = false; + } else if (m_mode == Mode::Hexfloat) { + base = 16; + upper_case = false; + } else if (m_mode == Mode::HexfloatUppercase) { + base = 16; + upper_case = true; + } else { + VERIFY_NOT_REACHED(); + } + + m_width = m_width.value_or(0); + m_precision = m_precision.value_or(6); + + i64 integer = value.ltrunk(); + constexpr u64 one = static_cast<Underlying>(1) << precision; + u64 fraction_raw = value.raw() & (one - 1); + return builder.put_fixed_point(integer, fraction_raw, one, base, upper_case, m_zero_pad, m_align, m_width.value(), m_precision.value(), m_fill, m_sign_mode); + } +}; + template<> struct Formatter<std::nullptr_t> : Formatter<FlatPtr> { ErrorOr<void> format(FormatBuilder& builder, std::nullptr_t) |