1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:48:14 +00:00

AK/Format: Compute TypeErasedParameter type and size at compile-time

Problem:
- Type and size information is known at compile-time, but computations
  are being performed using run-time parameters.

Solution:
- Move function arguments to be template arguments.
- Convert to `consteval` where possible.
- Decorate functions with `constexpr` which are used in both run-time
  and compile-time contexts.
This commit is contained in:
Lenny Maiorani 2021-04-21 13:47:03 -06:00 committed by Andreas Kling
parent 6cbf88ad4c
commit e117756d9f
2 changed files with 44 additions and 45 deletions

View file

@ -46,16 +46,16 @@ namespace AK {
namespace { namespace {
constexpr size_t use_next_index = NumericLimits<size_t>::max(); static constexpr size_t use_next_index = NumericLimits<size_t>::max();
// The worst case is that we have the largest 64-bit value formatted as binary number, this would take // The worst case is that we have the largest 64-bit value formatted as binary number, this would take
// 65 bytes. Choosing a larger power of two won't hurt and is a bit of mitigation against out-of-bounds accesses. // 65 bytes. Choosing a larger power of two won't hurt and is a bit of mitigation against out-of-bounds accesses.
inline size_t convert_unsigned_to_string(u64 value, Array<u8, 128>& buffer, u8 base, bool upper_case) static constexpr size_t convert_unsigned_to_string(u64 value, Array<u8, 128>& buffer, u8 base, bool upper_case)
{ {
VERIFY(base >= 2 && base <= 16); VERIFY(base >= 2 && base <= 16);
static constexpr const char* lowercase_lookup = "0123456789abcdef"; constexpr const char* lowercase_lookup = "0123456789abcdef";
static constexpr const char* uppercase_lookup = "0123456789ABCDEF"; constexpr const char* uppercase_lookup = "0123456789ABCDEF";
if (value == 0) { if (value == 0) {
buffer[0] = '0'; buffer[0] = '0';
@ -102,34 +102,6 @@ void vformat_impl(TypeErasedFormatParams& params, FormatBuilder& builder, Format
} // namespace AK::{anonymous} } // namespace AK::{anonymous}
size_t TypeErasedParameter::to_size() const
{
i64 svalue;
if (type == TypeErasedParameter::Type::UInt8)
svalue = *reinterpret_cast<const u8*>(value);
else if (type == TypeErasedParameter::Type::UInt16)
svalue = *reinterpret_cast<const u16*>(value);
else if (type == TypeErasedParameter::Type::UInt32)
svalue = *reinterpret_cast<const u32*>(value);
else if (type == TypeErasedParameter::Type::UInt64)
svalue = *reinterpret_cast<const u64*>(value);
else if (type == TypeErasedParameter::Type::Int8)
svalue = *reinterpret_cast<const i8*>(value);
else if (type == TypeErasedParameter::Type::Int16)
svalue = *reinterpret_cast<const i16*>(value);
else if (type == TypeErasedParameter::Type::Int32)
svalue = *reinterpret_cast<const i32*>(value);
else if (type == TypeErasedParameter::Type::Int64)
svalue = *reinterpret_cast<const i64*>(value);
else
VERIFY_NOT_REACHED();
VERIFY(svalue >= 0);
return static_cast<size_t>(svalue);
}
FormatParser::FormatParser(StringView input) FormatParser::FormatParser(StringView input)
: GenericLexer(input) : GenericLexer(input)
{ {

View file

@ -65,25 +65,26 @@ struct TypeErasedParameter {
Custom Custom
}; };
static Type get_type_from_size(size_t size, bool is_unsigned) template<size_t size, bool is_unsigned>
static consteval Type get_type_from_size()
{ {
if (is_unsigned) { if constexpr (is_unsigned) {
if (size == 1) if constexpr (size == 1)
return Type::UInt8; return Type::UInt8;
if (size == 2) if constexpr (size == 2)
return Type::UInt16; return Type::UInt16;
if (size == 4) if constexpr (size == 4)
return Type::UInt32; return Type::UInt32;
if (size == 8) if constexpr (size == 8)
return Type::UInt64; return Type::UInt64;
} else { } else {
if (size == 1) if constexpr (size == 1)
return Type::Int8; return Type::Int8;
if (size == 2) if constexpr (size == 2)
return Type::Int16; return Type::Int16;
if (size == 4) if constexpr (size == 4)
return Type::Int32; return Type::Int32;
if (size == 8) if constexpr (size == 8)
return Type::Int64; return Type::Int64;
} }
@ -91,15 +92,41 @@ struct TypeErasedParameter {
} }
template<typename T> template<typename T>
static Type get_type() static consteval Type get_type()
{ {
if constexpr (IsIntegral<T>) if constexpr (IsIntegral<T>)
return get_type_from_size(sizeof(T), IsUnsigned<T>); return get_type_from_size<sizeof(T), IsUnsigned<T>>();
else else
return Type::Custom; return Type::Custom;
} }
size_t to_size() const; constexpr size_t to_size() const
{
i64 svalue;
if (type == TypeErasedParameter::Type::UInt8)
svalue = *static_cast<const u8*>(value);
else if (type == TypeErasedParameter::Type::UInt16)
svalue = *static_cast<const u16*>(value);
else if (type == TypeErasedParameter::Type::UInt32)
svalue = *static_cast<const u32*>(value);
else if (type == TypeErasedParameter::Type::UInt64)
svalue = *static_cast<const u64*>(value);
else if (type == TypeErasedParameter::Type::Int8)
svalue = *static_cast<const i8*>(value);
else if (type == TypeErasedParameter::Type::Int16)
svalue = *static_cast<const i16*>(value);
else if (type == TypeErasedParameter::Type::Int32)
svalue = *static_cast<const i32*>(value);
else if (type == TypeErasedParameter::Type::Int64)
svalue = *static_cast<const i64*>(value);
else
VERIFY_NOT_REACHED();
VERIFY(svalue >= 0);
return static_cast<size_t>(svalue);
}
// FIXME: Getters and setters. // FIXME: Getters and setters.