0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00

src: enhance C++ sprintf utility

PR-URL: https://github.com/nodejs/node/pull/32385
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
This commit is contained in:
himself65 2020-03-20 16:23:02 +08:00 committed by Gabriel Schulhof
parent b950daf836
commit dade90db9c
3 changed files with 45 additions and 1 deletions

View File

@ -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 <unsigned BASE_BITS,
typename T,
typename std::enable_if<std::is_integral<T>::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<char>('0' + digit) : digits[digit]);
} while ((value >>= BASE_BITS) != 0);
return ptr;
}
template <unsigned BASE_BITS,
typename T,
typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
static std::string BaseConvert(T value) {
return Convert(std::forward<T>(value));
}
};
template <typename T>
@ -34,6 +55,11 @@ std::string ToString(const T& value) {
return ToStringHelper::Convert(value);
}
template <unsigned BASE_BITS, typename T>
std::string ToBaseString(T&& value) {
return ToStringHelper::BaseConvert<BASE_BITS>(std::forward<T>(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<typename std::remove_reference<Arg>::type>::value);
char out[20];

View File

@ -5,6 +5,7 @@
#include "async_wrap.h"
#include <algorithm>
#include <sstream>
#include <string>

View File

@ -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);