From 94952b4ac88264ed86378e20cf0bbe627c180cae Mon Sep 17 00:00:00 2001 From: himself65 Date: Fri, 20 Mar 2020 16:23:02 +0800 Subject: [PATCH] src: enhance C++ sprintf utility PR-URL: https://github.com/nodejs/node/pull/32385 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Gabriel Schulhof --- src/debug_utils-inl.h | 39 ++++++++++++++++++++++++++++++++++++++- src/debug_utils.h | 1 + test/cctest/test_util.cc | 6 ++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/debug_utils-inl.h b/src/debug_utils-inl.h index ae2d2046486466..470fdc3db955c6 100644 --- a/src/debug_utils-inl.h +++ b/src/debug_utils-inl.h @@ -27,6 +27,27 @@ struct ToStringHelper { } static std::string Convert(const std::string& value) { return value; } static std::string Convert(bool value) { return value ? "true" : "false"; } + template ::value, int>::type = 0> + static std::string BaseConvert(T value) { + char ret[3 * sizeof(T)]; + char* ptr = ret + 3 * sizeof(T) - 1; + *ptr = '\0'; + const char* digits = "0123456789abcdef"; + do { + unsigned digit = value & ((1 << BASE_BITS) - 1); + *--ptr = + (BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return ptr; + } + template ::value, int>::type = 0> + static std::string BaseConvert(T value) { + return Convert(std::forward(value)); + } }; template @@ -34,6 +55,11 @@ std::string ToString(const T& value) { return ToStringHelper::Convert(value); } +template +std::string ToBaseString(T&& value) { + return ToStringHelper::BaseConvert(std::forward(value)); +} + inline std::string SPrintFImpl(const char* format) { const char* p = strchr(format, '%'); if (LIKELY(p == nullptr)) return format; @@ -64,7 +90,18 @@ std::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string) case 'd': case 'i': case 'u': - case 's': ret += ToString(arg); break; + case 's': + ret += ToString(arg); + break; + case 'o': + ret += ToBaseString<3>(arg); + break; + case 'x': + ret += ToBaseString<4>(arg); + break; + case 'X': + ret += node::ToUpper(ToBaseString<4>(arg)); + break; case 'p': { CHECK(std::is_pointer::type>::value); char out[20]; diff --git a/src/debug_utils.h b/src/debug_utils.h index b74bd87b9b8991..ecc53b0c2b0aa0 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -5,6 +5,7 @@ #include "async_wrap.h" +#include #include #include diff --git a/test/cctest/test_util.cc b/test/cctest/test_util.cc index a38f549f0387dc..6cfd5d317f7982 100644 --- a/test/cctest/test_util.cc +++ b/test/cctest/test_util.cc @@ -268,6 +268,12 @@ TEST(UtilTest, SPrintF) { EXPECT_EQ(SPrintF("%u", -10000000000LL), "-10000000000"); EXPECT_EQ(SPrintF("%i", 10), "10"); EXPECT_EQ(SPrintF("%d", 10), "10"); + EXPECT_EQ(SPrintF("%x", 15), "f"); + EXPECT_EQ(SPrintF("%x", 16), "10"); + EXPECT_EQ(SPrintF("%X", 15), "F"); + EXPECT_EQ(SPrintF("%X", 16), "10"); + EXPECT_EQ(SPrintF("%o", 7), "7"); + EXPECT_EQ(SPrintF("%o", 8), "10"); EXPECT_EQ(atof(SPrintF("%s", 0.5).c_str()), 0.5); EXPECT_EQ(atof(SPrintF("%s", -0.5).c_str()), -0.5);