diff options
author | asynts <asynts@gmail.com> | 2020-09-27 18:09:14 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-09-28 10:53:16 +0200 |
commit | 56bfefabb6d1291a197aa4b0363ca4a46997e8b9 (patch) | |
tree | 5d58456cca621479c317a0411e374bdb8a579d88 /AK/Format.cpp | |
parent | 6a2f5f45226fd3979fac7deedca8b61618f09749 (diff) | |
download | serenity-56bfefabb6d1291a197aa4b0363ca4a46997e8b9.zip |
AK+Format: Keep type information for integers in TypeErasedParameter.
It's now save to pass a signed integer as parameter and then use it as
replacement field (previously, this would just cast it to size_t which
would be bad.)
Diffstat (limited to 'AK/Format.cpp')
-rw-r--r-- | AK/Format.cpp | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/AK/Format.cpp b/AK/Format.cpp index 1144a42065..79333aa907 100644 --- a/AK/Format.cpp +++ b/AK/Format.cpp @@ -168,6 +168,43 @@ void vformat_impl(StringBuilder& builder, FormatStringParser& parser, Span<const vformat_impl(builder, parser, parameters, argument_index); } +size_t decode_value(size_t value, Span<const AK::TypeErasedParameter> parameters) +{ + if (value == AK::StandardFormatter::value_from_next_arg) + TODO(); + + if (value >= AK::StandardFormatter::value_from_arg) { + const auto parameter = parameters.at(value - AK::StandardFormatter::value_from_arg); + + Optional<i64> svalue; + if (parameter.type == AK::TypeErasedParameter::Type::UInt8) + value = *reinterpret_cast<const u8*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::UInt16) + value = *reinterpret_cast<const u16*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::UInt32) + value = *reinterpret_cast<const u32*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::UInt64) + value = *reinterpret_cast<const u64*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::Int8) + svalue = *reinterpret_cast<const i8*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::Int16) + svalue = *reinterpret_cast<const i16*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::Int32) + svalue = *reinterpret_cast<const i32*>(parameter.value); + else if (parameter.type == AK::TypeErasedParameter::Type::Int64) + svalue = *reinterpret_cast<const i64*>(parameter.value); + else + ASSERT_NOT_REACHED(); + + if (svalue.has_value()) { + ASSERT(svalue.value() >= 0); + value = static_cast<size_t>(svalue.value()); + } + } + + return value; +} + } // namespace namespace AK { @@ -307,14 +344,7 @@ void Formatter<T, typename EnableIf<IsIntegral<T>::value>::Type>::format(StringB ASSERT_NOT_REACHED(); } - size_t width = m_width; - if (m_width >= value_from_arg) { - const auto parameter = parameters.at(m_width - value_from_arg); - - // FIXME: Totally unsave cast. We should store the type in TypeErasedParameter. For compactness it could be smart to - // find a few addresses that can not be valid function pointers and encode the type information there? - width = *reinterpret_cast<const size_t*>(parameter.value); - } + auto width = decode_value(m_width, parameters); PrintfImplementation::Align align; if (m_align == Align::Left) |