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