Skip to content

Commit 94952b4

Browse files
himself65MylesBorins
authored andcommitted
src: enhance C++ sprintf utility
PR-URL: #32385 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
1 parent e9e12b8 commit 94952b4

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

src/debug_utils-inl.h

+38-1
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,39 @@ struct ToStringHelper {
2727
}
2828
static std::string Convert(const std::string& value) { return value; }
2929
static std::string Convert(bool value) { return value ? "true" : "false"; }
30+
template <unsigned BASE_BITS,
31+
typename T,
32+
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
33+
static std::string BaseConvert(T value) {
34+
char ret[3 * sizeof(T)];
35+
char* ptr = ret + 3 * sizeof(T) - 1;
36+
*ptr = '\0';
37+
const char* digits = "0123456789abcdef";
38+
do {
39+
unsigned digit = value & ((1 << BASE_BITS) - 1);
40+
*--ptr =
41+
(BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]);
42+
} while ((value >>= BASE_BITS) != 0);
43+
return ptr;
44+
}
45+
template <unsigned BASE_BITS,
46+
typename T,
47+
typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
48+
static std::string BaseConvert(T value) {
49+
return Convert(std::forward<T>(value));
50+
}
3051
};
3152

3253
template <typename T>
3354
std::string ToString(const T& value) {
3455
return ToStringHelper::Convert(value);
3556
}
3657

58+
template <unsigned BASE_BITS, typename T>
59+
std::string ToBaseString(T&& value) {
60+
return ToStringHelper::BaseConvert<BASE_BITS>(std::forward<T>(value));
61+
}
62+
3763
inline std::string SPrintFImpl(const char* format) {
3864
const char* p = strchr(format, '%');
3965
if (LIKELY(p == nullptr)) return format;
@@ -64,7 +90,18 @@ std::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string)
6490
case 'd':
6591
case 'i':
6692
case 'u':
67-
case 's': ret += ToString(arg); break;
93+
case 's':
94+
ret += ToString(arg);
95+
break;
96+
case 'o':
97+
ret += ToBaseString<3>(arg);
98+
break;
99+
case 'x':
100+
ret += ToBaseString<4>(arg);
101+
break;
102+
case 'X':
103+
ret += node::ToUpper(ToBaseString<4>(arg));
104+
break;
68105
case 'p': {
69106
CHECK(std::is_pointer<typename std::remove_reference<Arg>::type>::value);
70107
char out[20];

src/debug_utils.h

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "async_wrap.h"
77

8+
#include <algorithm>
89
#include <sstream>
910
#include <string>
1011

test/cctest/test_util.cc

+6
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ TEST(UtilTest, SPrintF) {
268268
EXPECT_EQ(SPrintF("%u", -10000000000LL), "-10000000000");
269269
EXPECT_EQ(SPrintF("%i", 10), "10");
270270
EXPECT_EQ(SPrintF("%d", 10), "10");
271+
EXPECT_EQ(SPrintF("%x", 15), "f");
272+
EXPECT_EQ(SPrintF("%x", 16), "10");
273+
EXPECT_EQ(SPrintF("%X", 15), "F");
274+
EXPECT_EQ(SPrintF("%X", 16), "10");
275+
EXPECT_EQ(SPrintF("%o", 7), "7");
276+
EXPECT_EQ(SPrintF("%o", 8), "10");
271277

272278
EXPECT_EQ(atof(SPrintF("%s", 0.5).c_str()), 0.5);
273279
EXPECT_EQ(atof(SPrintF("%s", -0.5).c_str()), -0.5);

0 commit comments

Comments
 (0)