Просмотр исходного кода

AK+Format: Accept unsigned long in replacement fields.

I ran into this exact but at least twenty times in Serenity alone. The
C++ Standard dictates that 'unsigned long' and 'unsigned long long' are
distinct types even though on most platforms they are usually both 64
bit integers.

Also it wasn't possible to evaluate IsIntegral<T> for types that were
not integers since it used MakeUnsigned<T> internally.
asynts 4 лет назад
Родитель
Сommit
620b73b3d5
3 измененных файлов с 42 добавлено и 16 удалено
  1. 27 16
      AK/Format.h
  2. 4 0
      AK/StdLibExtras.h
  3. 11 0
      AK/Tests/TestFormat.cpp

+ 27 - 16
AK/Format.h

@@ -60,25 +60,36 @@ struct TypeErasedParameter {
         Custom
         Custom
     };
     };
 
 
+    static Type get_type_from_size(size_t size, bool is_unsigned)
+    {
+        if (is_unsigned) {
+            if (size == 1)
+                return Type::UInt8;
+            if (size == 2)
+                return Type::UInt16;
+            if (size == 4)
+                return Type::UInt32;
+            if (size == 8)
+                return Type::UInt64;
+        } else {
+            if (size == 1)
+                return Type::Int8;
+            if (size == 2)
+                return Type::Int16;
+            if (size == 4)
+                return Type::Int32;
+            if (size == 8)
+                return Type::Int64;
+        }
+
+        ASSERT_NOT_REACHED();
+    }
+
     template<typename T>
     template<typename T>
     static Type get_type()
     static Type get_type()
     {
     {
-        if (IsSame<T, u8>::value)
-            return Type::UInt8;
-        if (IsSame<T, u16>::value)
-            return Type::UInt16;
-        if (IsSame<T, u32>::value)
-            return Type::UInt32;
-        if (IsSame<T, u64>::value)
-            return Type::UInt64;
-        if (IsSame<T, i8>::value)
-            return Type::Int8;
-        if (IsSame<T, i16>::value)
-            return Type::Int16;
-        if (IsSame<T, i32>::value)
-            return Type::Int32;
-        if (IsSame<T, i64>::value)
-            return Type::Int64;
+        if (IsIntegral<T>::value)
+            return get_type_from_size(sizeof(T), IsUnsigned<T>::value);
 
 
         return Type::Custom;
         return Type::Custom;
     }
     }

+ 4 - 0
AK/StdLibExtras.h

@@ -326,6 +326,7 @@ constexpr T&& forward(typename RemoveReference<T>::Type&& param) noexcept
 
 
 template<typename T>
 template<typename T>
 struct MakeUnsigned {
 struct MakeUnsigned {
+    using Type = void;
 };
 };
 template<>
 template<>
 struct MakeUnsigned<signed char> {
 struct MakeUnsigned<signed char> {
@@ -507,6 +508,9 @@ using Void = void;
 template<typename... _Ignored>
 template<typename... _Ignored>
 constexpr auto DependentFalse = false;
 constexpr auto DependentFalse = false;
 
 
+template<typename T>
+using IsUnsigned = IsSame<T, MakeUnsigned<T>>;
+
 }
 }
 
 
 using AK::AddConst;
 using AK::AddConst;

+ 11 - 0
AK/Tests/TestFormat.cpp

@@ -29,6 +29,12 @@
 #include <AK/String.h>
 #include <AK/String.h>
 #include <AK/StringBuilder.h>
 #include <AK/StringBuilder.h>
 
 
+TEST_CASE(is_integral_works_properly)
+{
+    EXPECT(!IsIntegral<const char*>::value);
+    EXPECT(IsIntegral<unsigned long>::value);
+}
+
 TEST_CASE(format_string_literals)
 TEST_CASE(format_string_literals)
 {
 {
     EXPECT_EQ(String::formatted("prefix-{}-suffix", "abc"), "prefix-abc-suffix");
     EXPECT_EQ(String::formatted("prefix-{}-suffix", "abc"), "prefix-abc-suffix");
@@ -124,6 +130,11 @@ TEST_CASE(replacement_field)
     EXPECT_EQ(String::formatted("{:0{}}", 1, 3), "001");
     EXPECT_EQ(String::formatted("{:0{}}", 1, 3), "001");
 }
 }
 
 
+TEST_CASE(replacement_field_regression)
+{
+    EXPECT_EQ(String::formatted("{:{}}", "", static_cast<unsigned long>(6)), "      ");
+}
+
 TEST_CASE(complex_string_specifiers)
 TEST_CASE(complex_string_specifiers)
 {
 {
     EXPECT_EQ(String::formatted("{:.8}", "123456789"), "12345678");
     EXPECT_EQ(String::formatted("{:.8}", "123456789"), "12345678");