diff --git a/src/debug_utils-inl.h b/src/debug_utils-inl.h index 3736663d9977c0..ecabec57dea95d 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); } @@ -97,7 +118,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 e1768d8a06159c..5d6e14f10f4d4b 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 diff --git a/src/util-inl.h b/src/util-inl.h index b55dc25b98c551..9d4db311024c5f 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -194,10 +194,14 @@ char ToLower(char c) { return std::tolower(c, std::locale::classic()); } -std::string ToLower(const std::string& in) { - std::string out(in.size(), 0); - for (size_t i = 0; i < in.size(); ++i) - out[i] = ToLower(in[i]); +template +std::string ToLower(const T& in) { + auto it = std::cbegin(in); + auto end = std::cend(in); + std::string out(std::distance(it, end), 0); + size_t i; + for (i = 0; it != end; ++it, ++i) out[i] = ToLower(*it); + DCHECK_EQ(i, out.size()); return out; } @@ -205,10 +209,14 @@ char ToUpper(char c) { return std::toupper(c, std::locale::classic()); } -std::string ToUpper(const std::string& in) { - std::string out(in.size(), 0); - for (size_t i = 0; i < in.size(); ++i) - out[i] = ToUpper(in[i]); +template +std::string ToUpper(const T& in) { + auto it = std::cbegin(in); + auto end = std::cend(in); + std::string out(std::distance(it, end), 0); + size_t i; + for (i = 0; it != end; ++it, ++i) out[i] = ToUpper(*it); + DCHECK_EQ(i, out.size()); return out; } diff --git a/src/util.h b/src/util.h index 0c061848829393..9144d9dea74105 100644 --- a/src/util.h +++ b/src/util.h @@ -366,11 +366,13 @@ inline v8::Local FIXED_ONE_BYTE_STRING(v8::Isolate* isolate, // tolower() is locale-sensitive. Use ToLower() instead. inline char ToLower(char c); -inline std::string ToLower(const std::string& in); +template +inline std::string ToLower(const T& in); // toupper() is locale-sensitive. Use ToUpper() instead. inline char ToUpper(char c); -inline std::string ToUpper(const std::string& in); +template +inline std::string ToUpper(const T& in); // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. inline bool StringEqualNoCase(const char* a, const char* b);