From 625d6928a863cdc60a907d5fcaf03dee60d25c8a Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Thu, 18 May 2023 08:19:24 +0000 Subject: [PATCH] [libc] Extend IntegerToString to convert UInt* numbers to hex string. 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 | 29 ++++++++++++++- libc/test/src/__support/CMakeLists.txt | 2 ++ libc/test/src/__support/integer_to_string_test.cpp | 41 ++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/libc/src/__support/integer_to_string.h b/libc/src/__support/integer_to_string.h index a748575..22c5ace 100644 --- a/libc/src/__support/integer_to_string.h +++ b/libc/src/__support/integer_to_string.h @@ -157,12 +157,39 @@ public: return convert<10>(val, buffer); } - template , int> = 0> + template && + (sizeof(T) <= sizeof(uintmax_t)), + int> = 0> LIBC_INLINE static cpp::optional hex(T val, cpp::span buffer, bool lowercase = true) { return convert<16>(val, buffer, lowercase); } + template && cpp::is_unsigned_v && + (sizeof(T) > sizeof(uintmax_t)) && + sizeof(T) % sizeof(uintmax_t) == 0, + int> = 0> + LIBC_INLINE static cpp::optional + hex(T val, cpp::span 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(val); + hex(block_val, + buffer.subspan((BLOCKS - i - 1) * UINTMAX_BUFSIZE, UINTMAX_BUFSIZE), + lowercase); + } + return cpp::string_view(buffer.data(), buffer.size()); + } + template , int> = 0> LIBC_INLINE static cpp::optional oct(T val, cpp::span buffer) { diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index 7390ed2..154ebfe 100644 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -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. diff --git a/libc/test/src/__support/integer_to_string_test.cpp b/libc/test/src/__support/integer_to_string_test.cpp index 26d9f6b..783a4d8 100644 --- a/libc/test/src/__support/integer_to_string_test.cpp +++ b/libc/test/src/__support/integer_to_string_test.cpp @@ -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()]; + EXPECT_EQ(*IntegerToString::hex(static_cast(0), buf), + string_view("00000000000000000000000000000000")); + EXPECT_EQ(*IntegerToString::hex(static_cast(0x12345), buf), + string_view("00000000000000000000000000012345")); + EXPECT_EQ((*IntegerToString::hex(static_cast(0x1234) << 112, buf)), + string_view("12340000000000000000000000000000")); + EXPECT_EQ((*IntegerToString::hex(static_cast(0x1234) << 48, buf)), + string_view("00000000000000001234000000000000")); + EXPECT_EQ((*IntegerToString::hex(static_cast(0x1234) << 52, buf)), + string_view("00000000000000012340000000000000")); +} + +TEST(LlvmLibcIntegerToStringTest, UINT256_Base_16) { + using UInt256 = __llvm_libc::cpp::UInt<256>; + char buf[IntegerToString::hex_bufsize()]; + EXPECT_EQ( + *IntegerToString::hex(static_cast(0), buf), + string_view( + "0000000000000000000000000000000000000000000000000000000000000000")); + EXPECT_EQ( + *IntegerToString::hex(static_cast(0x12345), buf), + string_view( + "0000000000000000000000000000000000000000000000000000000000012345")); + EXPECT_EQ( + (*IntegerToString::hex(static_cast(0x1234) << 112, buf)), + string_view( + "0000000000000000000000000000000012340000000000000000000000000000")); + EXPECT_EQ( + (*IntegerToString::hex(static_cast(0x1234) << 116, buf)), + string_view( + "0000000000000000000000000000000123400000000000000000000000000000")); + EXPECT_EQ( + (*IntegerToString::hex(static_cast(0x1234) << 240, buf)), + string_view( + "1234000000000000000000000000000000000000000000000000000000000000")); +} -- 2.7.4