summaryrefslogtreecommitdiff
path: root/AK/Format.cpp
diff options
context:
space:
mode:
authorasynts <asynts@gmail.com>2020-09-27 18:09:14 +0200
committerAndreas Kling <kling@serenityos.org>2020-09-28 10:53:16 +0200
commit56bfefabb6d1291a197aa4b0363ca4a46997e8b9 (patch)
tree5d58456cca621479c317a0411e374bdb8a579d88 /AK/Format.cpp
parent6a2f5f45226fd3979fac7deedca8b61618f09749 (diff)
downloadserenity-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.cpp46
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)