From 4a9a022dd43cc407470d8fb175cb1c78728cec96 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 28 Sep 2025 03:21:07 +0200 Subject: [PATCH] src: avoid unnecessary string allocations in SPrintF impl If we can use a `std::string_view` instead of a `std::string`, let's just do that instead. PR-URL: https://github.com/nodejs/node/pull/60052 Reviewed-By: James M Snell Reviewed-By: Rafael Gonzaga --- src/debug_utils-inl.h | 45 +++++++++++++++++++++++++++++++------------ src/debug_utils.h | 2 ++ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/debug_utils-inl.h b/src/debug_utils-inl.h index a687708d92..c10af8b1b6 100644 --- a/src/debug_utils-inl.h +++ b/src/debug_utils-inl.h @@ -11,25 +11,41 @@ namespace node { +template +concept StringViewConvertible = requires(T a) { + { + a.ToStringView() + } -> std::convertible_to; + }; +template +concept StringConvertible = requires(T a) { + { + a.ToString() + } -> std::convertible_to; + }; + struct ToStringHelper { template - static std::string Convert( - const T& value, - std::string(T::* to_string)() const = &T::ToString) { - return (value.*to_string)(); + requires(StringConvertible) && (!StringViewConvertible) + static std::string Convert(const T& value) { + return value.ToString(); } + template + requires StringViewConvertible + static std::string_view Convert(const T& value) { + return value.ToStringView(); + } + template ::value, bool>::type, typename dummy = bool> static std::string Convert(const T& value) { return std::to_string(value); } - static std::string Convert(const char* value) { + static std::string_view Convert(const char* value) { return value != nullptr ? value : "(null)"; } static std::string Convert(const std::string& value) { return value; } - static std::string Convert(std::string_view value) { - return std::string(value); - } + static std::string_view Convert(std::string_view value) { return value; } static std::string Convert(bool value) { return value ? "true" : "false"; } template >> - static std::string BaseConvert(T& value) { // NOLINT(runtime/references) + static auto BaseConvert(T&& value) { return Convert(std::forward(value)); } }; template -std::string ToString(const T& value) { +auto ToStringOrStringView(const T& value) { return ToStringHelper::Convert(value); } +template +std::string ToString(const T& value) { + return std::string(ToStringOrStringView(value)); +} + template -std::string ToBaseString(const T& value) { +auto ToBaseString(const T& value) { return ToStringHelper::BaseConvert(value); } @@ -106,7 +127,7 @@ std::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string) case 'i': case 'u': case 's': - ret += ToString(arg); + ret += ToStringOrStringView(arg); break; case 'o': ret += ToBaseString<3>(arg); diff --git a/src/debug_utils.h b/src/debug_utils.h index 930539d3cb..8f6165e1b5 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -26,6 +26,8 @@ class Environment; template inline std::string ToString(const T& value); +template +inline auto ToStringOrStringView(const T& value); // C++-style variant of sprintf()/fprintf() that: // - Returns an std::string