11cb0ef41Sopenharmony_ci#ifndef SRC_DEBUG_UTILS_INL_H_ 21cb0ef41Sopenharmony_ci#define SRC_DEBUG_UTILS_INL_H_ 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci#include "debug_utils.h" 71cb0ef41Sopenharmony_ci#include "env.h" 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include <type_traits> 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_cinamespace node { 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_cistruct ToStringHelper { 141cb0ef41Sopenharmony_ci template <typename T> 151cb0ef41Sopenharmony_ci static std::string Convert( 161cb0ef41Sopenharmony_ci const T& value, 171cb0ef41Sopenharmony_ci std::string(T::* to_string)() const = &T::ToString) { 181cb0ef41Sopenharmony_ci return (value.*to_string)(); 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci template <typename T, 211cb0ef41Sopenharmony_ci typename test_for_number = typename std:: 221cb0ef41Sopenharmony_ci enable_if<std::is_arithmetic<T>::value, bool>::type, 231cb0ef41Sopenharmony_ci typename dummy = bool> 241cb0ef41Sopenharmony_ci static std::string Convert(const T& value) { return std::to_string(value); } 251cb0ef41Sopenharmony_ci static std::string Convert(const char* value) { 261cb0ef41Sopenharmony_ci return value != nullptr ? value : "(null)"; 271cb0ef41Sopenharmony_ci } 281cb0ef41Sopenharmony_ci static std::string Convert(const std::string& value) { return value; } 291cb0ef41Sopenharmony_ci static std::string Convert(std::string_view value) { 301cb0ef41Sopenharmony_ci return std::string(value); 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci static std::string Convert(bool value) { return value ? "true" : "false"; } 331cb0ef41Sopenharmony_ci template <unsigned BASE_BITS, 341cb0ef41Sopenharmony_ci typename T, 351cb0ef41Sopenharmony_ci typename = std::enable_if_t<std::is_integral_v<T>>> 361cb0ef41Sopenharmony_ci static std::string BaseConvert(const T& value) { 371cb0ef41Sopenharmony_ci auto v = static_cast<uint64_t>(value); 381cb0ef41Sopenharmony_ci char ret[3 * sizeof(T)]; 391cb0ef41Sopenharmony_ci char* ptr = ret + 3 * sizeof(T) - 1; 401cb0ef41Sopenharmony_ci *ptr = '\0'; 411cb0ef41Sopenharmony_ci const char* digits = "0123456789abcdef"; 421cb0ef41Sopenharmony_ci do { 431cb0ef41Sopenharmony_ci unsigned digit = v & ((1 << BASE_BITS) - 1); 441cb0ef41Sopenharmony_ci *--ptr = 451cb0ef41Sopenharmony_ci (BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]); 461cb0ef41Sopenharmony_ci } while ((v >>= BASE_BITS) != 0); 471cb0ef41Sopenharmony_ci return ptr; 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci template <unsigned BASE_BITS, 501cb0ef41Sopenharmony_ci typename T, 511cb0ef41Sopenharmony_ci typename = std::enable_if_t<!std::is_integral_v<T>>> 521cb0ef41Sopenharmony_ci static std::string BaseConvert(T value) { 531cb0ef41Sopenharmony_ci return Convert(std::forward<T>(value)); 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci}; 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_citemplate <typename T> 581cb0ef41Sopenharmony_cistd::string ToString(const T& value) { 591cb0ef41Sopenharmony_ci return ToStringHelper::Convert(value); 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_citemplate <unsigned BASE_BITS, typename T> 631cb0ef41Sopenharmony_cistd::string ToBaseString(const T& value) { 641cb0ef41Sopenharmony_ci return ToStringHelper::BaseConvert<BASE_BITS>(value); 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ciinline std::string SPrintFImpl(const char* format) { 681cb0ef41Sopenharmony_ci const char* p = strchr(format, '%'); 691cb0ef41Sopenharmony_ci if (LIKELY(p == nullptr)) return format; 701cb0ef41Sopenharmony_ci CHECK_EQ(p[1], '%'); // Only '%%' allowed when there are no arguments. 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci return std::string(format, p + 1) + SPrintFImpl(p + 2); 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_citemplate <typename Arg, typename... Args> 761cb0ef41Sopenharmony_cistd::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string) 771cb0ef41Sopenharmony_ci const char* format, Arg&& arg, Args&&... args) { 781cb0ef41Sopenharmony_ci const char* p = strchr(format, '%'); 791cb0ef41Sopenharmony_ci CHECK_NOT_NULL(p); // If you hit this, you passed in too many arguments. 801cb0ef41Sopenharmony_ci std::string ret(format, p); 811cb0ef41Sopenharmony_ci // Ignore long / size_t modifiers 821cb0ef41Sopenharmony_ci while (strchr("lz", *++p) != nullptr) {} 831cb0ef41Sopenharmony_ci switch (*p) { 841cb0ef41Sopenharmony_ci case '%': { 851cb0ef41Sopenharmony_ci return ret + '%' + SPrintFImpl(p + 1, 861cb0ef41Sopenharmony_ci std::forward<Arg>(arg), 871cb0ef41Sopenharmony_ci std::forward<Args>(args)...); 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci default: { 901cb0ef41Sopenharmony_ci return ret + '%' + SPrintFImpl(p, 911cb0ef41Sopenharmony_ci std::forward<Arg>(arg), 921cb0ef41Sopenharmony_ci std::forward<Args>(args)...); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci case 'd': 951cb0ef41Sopenharmony_ci case 'i': 961cb0ef41Sopenharmony_ci case 'u': 971cb0ef41Sopenharmony_ci case 's': 981cb0ef41Sopenharmony_ci ret += ToString(arg); 991cb0ef41Sopenharmony_ci break; 1001cb0ef41Sopenharmony_ci case 'o': 1011cb0ef41Sopenharmony_ci ret += ToBaseString<3>(arg); 1021cb0ef41Sopenharmony_ci break; 1031cb0ef41Sopenharmony_ci case 'x': 1041cb0ef41Sopenharmony_ci ret += ToBaseString<4>(arg); 1051cb0ef41Sopenharmony_ci break; 1061cb0ef41Sopenharmony_ci case 'X': 1071cb0ef41Sopenharmony_ci ret += node::ToUpper(ToBaseString<4>(arg)); 1081cb0ef41Sopenharmony_ci break; 1091cb0ef41Sopenharmony_ci case 'p': { 1101cb0ef41Sopenharmony_ci CHECK(std::is_pointer<typename std::remove_reference<Arg>::type>::value); 1111cb0ef41Sopenharmony_ci char out[20]; 1121cb0ef41Sopenharmony_ci int n = snprintf(out, 1131cb0ef41Sopenharmony_ci sizeof(out), 1141cb0ef41Sopenharmony_ci "%p", 1151cb0ef41Sopenharmony_ci *reinterpret_cast<const void* const*>(&arg)); 1161cb0ef41Sopenharmony_ci CHECK_GE(n, 0); 1171cb0ef41Sopenharmony_ci ret += out; 1181cb0ef41Sopenharmony_ci break; 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci return ret + SPrintFImpl(p + 1, std::forward<Args>(args)...); 1221cb0ef41Sopenharmony_ci} 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_citemplate <typename... Args> 1251cb0ef41Sopenharmony_cistd::string COLD_NOINLINE SPrintF( // NOLINT(runtime/string) 1261cb0ef41Sopenharmony_ci const char* format, Args&&... args) { 1271cb0ef41Sopenharmony_ci return SPrintFImpl(format, std::forward<Args>(args)...); 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_citemplate <typename... Args> 1311cb0ef41Sopenharmony_civoid COLD_NOINLINE FPrintF(FILE* file, const char* format, Args&&... args) { 1321cb0ef41Sopenharmony_ci FWrite(file, SPrintF(format, std::forward<Args>(args)...)); 1331cb0ef41Sopenharmony_ci} 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_citemplate <typename... Args> 1361cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(EnabledDebugList* list, 1371cb0ef41Sopenharmony_ci DebugCategory cat, 1381cb0ef41Sopenharmony_ci const char* format, 1391cb0ef41Sopenharmony_ci Args&&... args) { 1401cb0ef41Sopenharmony_ci if (!UNLIKELY(list->enabled(cat))) return; 1411cb0ef41Sopenharmony_ci FPrintF(stderr, format, std::forward<Args>(args)...); 1421cb0ef41Sopenharmony_ci} 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(EnabledDebugList* list, 1451cb0ef41Sopenharmony_ci DebugCategory cat, 1461cb0ef41Sopenharmony_ci const char* message) { 1471cb0ef41Sopenharmony_ci if (!UNLIKELY(list->enabled(cat))) return; 1481cb0ef41Sopenharmony_ci FPrintF(stderr, "%s", message); 1491cb0ef41Sopenharmony_ci} 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_citemplate <typename... Args> 1521cb0ef41Sopenharmony_ciinline void FORCE_INLINE 1531cb0ef41Sopenharmony_ciDebug(Environment* env, DebugCategory cat, const char* format, Args&&... args) { 1541cb0ef41Sopenharmony_ci Debug(env->enabled_debug_list(), cat, format, std::forward<Args>(args)...); 1551cb0ef41Sopenharmony_ci} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(Environment* env, 1581cb0ef41Sopenharmony_ci DebugCategory cat, 1591cb0ef41Sopenharmony_ci const char* message) { 1601cb0ef41Sopenharmony_ci Debug(env->enabled_debug_list(), cat, message); 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_citemplate <typename... Args> 1641cb0ef41Sopenharmony_ciinline void Debug(Environment* env, 1651cb0ef41Sopenharmony_ci DebugCategory cat, 1661cb0ef41Sopenharmony_ci const std::string& format, 1671cb0ef41Sopenharmony_ci Args&&... args) { 1681cb0ef41Sopenharmony_ci Debug(env->enabled_debug_list(), 1691cb0ef41Sopenharmony_ci cat, 1701cb0ef41Sopenharmony_ci format.c_str(), 1711cb0ef41Sopenharmony_ci std::forward<Args>(args)...); 1721cb0ef41Sopenharmony_ci} 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that 1751cb0ef41Sopenharmony_ci// the FORCE_INLINE flag on them doesn't apply to the contents of this function 1761cb0ef41Sopenharmony_ci// as well. 1771cb0ef41Sopenharmony_ci// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing 1781cb0ef41Sopenharmony_ci// this function for speed and it should rather focus on keeping it out of 1791cb0ef41Sopenharmony_ci// hot code paths. In particular, we want to keep the string concatenating code 1801cb0ef41Sopenharmony_ci// out of the function containing the original `Debug()` call. 1811cb0ef41Sopenharmony_citemplate <typename... Args> 1821cb0ef41Sopenharmony_civoid COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap, 1831cb0ef41Sopenharmony_ci const char* format, 1841cb0ef41Sopenharmony_ci Args&&... args) { 1851cb0ef41Sopenharmony_ci Debug(async_wrap->env(), 1861cb0ef41Sopenharmony_ci static_cast<DebugCategory>(async_wrap->provider_type()), 1871cb0ef41Sopenharmony_ci async_wrap->diagnostic_name() + " " + format + "\n", 1881cb0ef41Sopenharmony_ci std::forward<Args>(args)...); 1891cb0ef41Sopenharmony_ci} 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_citemplate <typename... Args> 1921cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(AsyncWrap* async_wrap, 1931cb0ef41Sopenharmony_ci const char* format, 1941cb0ef41Sopenharmony_ci Args&&... args) { 1951cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(async_wrap); 1961cb0ef41Sopenharmony_ci DebugCategory cat = static_cast<DebugCategory>(async_wrap->provider_type()); 1971cb0ef41Sopenharmony_ci if (!UNLIKELY(async_wrap->env()->enabled_debug_list()->enabled(cat))) return; 1981cb0ef41Sopenharmony_ci UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...); 1991cb0ef41Sopenharmony_ci} 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_citemplate <typename... Args> 2021cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(AsyncWrap* async_wrap, 2031cb0ef41Sopenharmony_ci const std::string& format, 2041cb0ef41Sopenharmony_ci Args&&... args) { 2051cb0ef41Sopenharmony_ci Debug(async_wrap, format.c_str(), std::forward<Args>(args)...); 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_cinamespace per_process { 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_citemplate <typename... Args> 2111cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(DebugCategory cat, 2121cb0ef41Sopenharmony_ci const char* format, 2131cb0ef41Sopenharmony_ci Args&&... args) { 2141cb0ef41Sopenharmony_ci Debug(&enabled_debug_list, cat, format, std::forward<Args>(args)...); 2151cb0ef41Sopenharmony_ci} 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(DebugCategory cat, const char* message) { 2181cb0ef41Sopenharmony_ci Debug(&enabled_debug_list, cat, message); 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci} // namespace per_process 2221cb0ef41Sopenharmony_ci} // namespace node 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci#endif // SRC_DEBUG_UTILS_INL_H_ 227