Skip to content

Commit

Permalink
src: enhance C++ sprintf utility
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
himself65 authored and Gabriel Schulhof committed Mar 26, 2020
1 parent b950daf commit dade90d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 1 deletion.
39 changes: 38 additions & 1 deletion src/debug_utils-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,39 @@ 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>
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;
Expand Down Expand Up @@ -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];
Expand Down
1 change: 1 addition & 0 deletions src/debug_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "async_wrap.h"

#include <algorithm>
#include <sstream>
#include <string>

Expand Down
6 changes: 6 additions & 0 deletions test/cctest/test_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit dade90d

Please sign in to comment.