[libc] Extend IntegerToString to convert UInt* numbers to hex string.
authorSiva Chandra Reddy <sivachandra@google.com>
Thu, 18 May 2023 08:19:24 +0000 (08:19 +0000)
committerSiva Chandra Reddy <sivachandra@google.com>
Thu, 18 May 2023 16:44:43 +0000 (16:44 +0000)
This new functionality will help us avoid duplicated code in various
places in the testing infrastructure. Since the string representation
of the wide numbers is to be used by tests, to keep it simple, we
zero-pad the strings.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D150849

libc/src/__support/integer_to_string.h
libc/test/src/__support/CMakeLists.txt
libc/test/src/__support/integer_to_string_test.cpp

index a748575..22c5ace 100644 (file)
@@ -157,12 +157,39 @@ public:
     return convert<10>(val, buffer);
   }
 
-  template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
+  template <typename T, cpp::enable_if_t<cpp::is_integral_v<T> &&
+                                             (sizeof(T) <= sizeof(uintmax_t)),
+                                         int> = 0>
   LIBC_INLINE static cpp::optional<cpp::string_view>
   hex(T val, cpp::span<char> buffer, bool lowercase = true) {
     return convert<16>(val, buffer, lowercase);
   }
 
+  template <typename T,
+            cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T> &&
+                                 (sizeof(T) > sizeof(uintmax_t)) &&
+                                 sizeof(T) % sizeof(uintmax_t) == 0,
+                             int> = 0>
+  LIBC_INLINE static cpp::optional<cpp::string_view>
+  hex(T val, cpp::span<char> buffer, bool lowercase = true) {
+    // We will assume the buffer is exactly sized, which will be the case if
+    // it was sized using the bufsize method.
+    constexpr size_t BLOCKS = sizeof(T) / sizeof(uintmax_t);
+    constexpr size_t UINTMAX_BUFSIZE = bufsize<16, uintmax_t>();
+    // We will zero out the buffer. This specialization is not used to
+    // implement a public function so zeroing out byte-by-byte does not
+    // have any affect on runtime or user expectations.
+    for (size_t i = 0; i < buffer.size(); ++i)
+      buffer[i] = '0';
+    for (size_t i = 0; i < BLOCKS; ++i, val >>= (sizeof(uintmax_t) * 8)) {
+      uintmax_t block_val = static_cast<uintmax_t>(val);
+      hex(block_val,
+          buffer.subspan((BLOCKS - i - 1) * UINTMAX_BUFSIZE, UINTMAX_BUFSIZE),
+          lowercase);
+    }
+    return cpp::string_view(buffer.data(), buffer.size());
+  }
+
   template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
   LIBC_INLINE static cpp::optional<cpp::string_view>
   oct(T val, cpp::span<char> buffer) {
index 7390ed2..154ebfe 100644 (file)
@@ -55,6 +55,8 @@ add_libc_test(
   DEPENDS
     libc.src.__support.integer_to_string
     libc.src.__support.CPP.string_view
+    libc.src.__support.uint
+    libc.src.__support.uint128
 )
 
 # The GPU does not support varargs currently.
index 26d9f6b..783a4d8 100644 (file)
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/__support/CPP/string_view.h"
+#include "src/__support/UInt.h"
+#include "src/__support/UInt128.h"
 #include "src/__support/integer_to_string.h"
 
 #include "test/UnitTest/Test.h"
@@ -247,3 +249,42 @@ TEST(LlvmLibcIntegerToStringTest, UINT64_Base_36) {
   EXPECT_EQ(*IntegerToString::convert<36>(uint64_t(0xffffffffffffffff), buf),
             string_view("3w5e11264sgsf"));
 }
+
+TEST(LlvmLibcIntegerToStringTest, UINT128_Base_16) {
+  char buf[IntegerToString::hex_bufsize<UInt128>()];
+  EXPECT_EQ(*IntegerToString::hex(static_cast<UInt128>(0), buf),
+            string_view("00000000000000000000000000000000"));
+  EXPECT_EQ(*IntegerToString::hex(static_cast<UInt128>(0x12345), buf),
+            string_view("00000000000000000000000000012345"));
+  EXPECT_EQ((*IntegerToString::hex(static_cast<UInt128>(0x1234) << 112, buf)),
+            string_view("12340000000000000000000000000000"));
+  EXPECT_EQ((*IntegerToString::hex(static_cast<UInt128>(0x1234) << 48, buf)),
+            string_view("00000000000000001234000000000000"));
+  EXPECT_EQ((*IntegerToString::hex(static_cast<UInt128>(0x1234) << 52, buf)),
+            string_view("00000000000000012340000000000000"));
+}
+
+TEST(LlvmLibcIntegerToStringTest, UINT256_Base_16) {
+  using UInt256 = __llvm_libc::cpp::UInt<256>;
+  char buf[IntegerToString::hex_bufsize<UInt256>()];
+  EXPECT_EQ(
+      *IntegerToString::hex(static_cast<UInt256>(0), buf),
+      string_view(
+          "0000000000000000000000000000000000000000000000000000000000000000"));
+  EXPECT_EQ(
+      *IntegerToString::hex(static_cast<UInt256>(0x12345), buf),
+      string_view(
+          "0000000000000000000000000000000000000000000000000000000000012345"));
+  EXPECT_EQ(
+      (*IntegerToString::hex(static_cast<UInt256>(0x1234) << 112, buf)),
+      string_view(
+          "0000000000000000000000000000000012340000000000000000000000000000"));
+  EXPECT_EQ(
+      (*IntegerToString::hex(static_cast<UInt256>(0x1234) << 116, buf)),
+      string_view(
+          "0000000000000000000000000000000123400000000000000000000000000000"));
+  EXPECT_EQ(
+      (*IntegerToString::hex(static_cast<UInt256>(0x1234) << 240, buf)),
+      string_view(
+          "1234000000000000000000000000000000000000000000000000000000000000"));
+}