diff --git a/libc/src/__support/integer_to_string.h b/libc/src/__support/integer_to_string.h --- a/libc/src/__support/integer_to_string.h +++ b/libc/src/__support/integer_to_string.h @@ -157,12 +157,39 @@ 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 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -55,6 +55,8 @@ 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 --- 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 @@ 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")); +}