GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: debug_utils-inl.h Lines: 75 82 91.5 %
Date: 2022-12-31 04:22:30 Branches: 201 263 76.4 %

Line Branch Exec Source
1
#ifndef SRC_DEBUG_UTILS_INL_H_
2
#define SRC_DEBUG_UTILS_INL_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "debug_utils.h"
7
#include "env.h"
8
9
#include <type_traits>
10
11
namespace node {
12
13
struct ToStringHelper {
14
  template <typename T>
15
1027
  static std::string Convert(
16
      const T& value,
17
      std::string(T::* to_string)() const = &T::ToString) {
18
1027
    return (value.*to_string)();
19
  }
20
  template <typename T,
21
            typename test_for_number = typename std::
22
                enable_if<std::is_arithmetic<T>::value, bool>::type,
23
            typename dummy = bool>
24
55764
  static std::string Convert(const T& value) { return std::to_string(value); }
25
2969
  static std::string Convert(const char* value) {
26
2969
    return value != nullptr ? value : "(null)";
27
  }
28
6365
  static std::string Convert(const std::string& value) { return value; }
29
  static std::string Convert(std::string_view value) {
30
    return std::string(value);
31
  }
32
56
  static std::string Convert(bool value) { return value ? "true" : "false"; }
33
  template <unsigned BASE_BITS,
34
            typename T,
35
            typename = std::enable_if_t<std::is_integral_v<T>>>
36
12
  static std::string BaseConvert(const T& value) {
37
12
    auto v = static_cast<uint64_t>(value);
38
    char ret[3 * sizeof(T)];
39
12
    char* ptr = ret + 3 * sizeof(T) - 1;
40
12
    *ptr = '\0';
41
12
    const char* digits = "0123456789abcdef";
42
6
    do {
43
18
      unsigned digit = v & ((1 << BASE_BITS) - 1);
44
18
      *--ptr =
45
6
          (BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]);
46
18
    } while ((v >>= BASE_BITS) != 0);
47
12
    return ptr;
48
  }
49
  template <unsigned BASE_BITS,
50
            typename T,
51
            typename = std::enable_if_t<!std::is_integral_v<T>>>
52
  static std::string BaseConvert(T value) {
53
    return Convert(std::forward<T>(value));
54
  }
55
};
56
57
template <typename T>
58
67871
std::string ToString(const T& value) {
59
67871
  return ToStringHelper::Convert(value);
60
}
61
62
template <unsigned BASE_BITS, typename T>
63
12
std::string ToBaseString(const T& value) {
64
12
  return ToStringHelper::BaseConvert<BASE_BITS>(value);
65
}
66
67
17306
inline std::string SPrintFImpl(const char* format) {
68
17306
  const char* p = strchr(format, '%');
69
17306
  if (LIKELY(p == nullptr)) return format;
70
1
  CHECK_EQ(p[1], '%');  // Only '%%' allowed when there are no arguments.
71
72
1
  return std::string(format, p + 1) + SPrintFImpl(p + 2);
73
}
74
75
template <typename Arg, typename... Args>
76
75052
std::string COLD_NOINLINE SPrintFImpl(  // NOLINT(runtime/string)
77
    const char* format, Arg&& arg, Args&&... args) {
78
75052
  const char* p = strchr(format, '%');
79
75052
  CHECK_NOT_NULL(p);  // If you hit this, you passed in too many arguments.
80
225156
  std::string ret(format, p);
81
  // Ignore long / size_t modifiers
82
75230
  while (strchr("lz", *++p) != nullptr) {}
83

75052
  switch (*p) {
84
2
    case '%': {
85
      return ret + '%' + SPrintFImpl(p + 1,
86
                                     std::forward<Arg>(arg),
87
2
                                     std::forward<Args>(args)...);
88
    }
89
    default: {
90
      return ret + '%' + SPrintFImpl(p,
91
                                     std::forward<Arg>(arg),
92
                                     std::forward<Args>(args)...);
93
    }
94
75034
    case 'd':
95
    case 'i':
96
    case 'u':
97
    case 's':
98
75034
      ret += ToString(arg);
99
75034
      break;
100
4
    case 'o':
101
4
      ret += ToBaseString<3>(arg);
102
4
      break;
103
4
    case 'x':
104
4
      ret += ToBaseString<4>(arg);
105
4
      break;
106
4
    case 'X':
107
4
      ret += node::ToUpper(ToBaseString<4>(arg));
108
4
      break;
109
4
    case 'p': {
110
      CHECK(std::is_pointer<typename std::remove_reference<Arg>::type>::value);
111
      char out[20];
112
4
      int n = snprintf(out,
113
                       sizeof(out),
114
                       "%p",
115
                       *reinterpret_cast<const void* const*>(&arg));
116
4
      CHECK_GE(n, 0);
117
4
      ret += out;
118
4
      break;
119
    }
120
  }
121
75050
  return ret + SPrintFImpl(p + 1, std::forward<Args>(args)...);
122
}
123
124
template <typename... Args>
125
27023
std::string COLD_NOINLINE SPrintF(  // NOLINT(runtime/string)
126
    const char* format, Args&&... args) {
127
27023
  return SPrintFImpl(format, std::forward<Args>(args)...);
128
}
129
130
template <typename... Args>
131
5374
void COLD_NOINLINE FPrintF(FILE* file, const char* format, Args&&... args) {
132
5374
  FWrite(file, SPrintF(format, std::forward<Args>(args)...));
133
5374
}
134
135
template <typename... Args>
136
inline void FORCE_INLINE Debug(EnabledDebugList* list,
137
                               DebugCategory cat,
138
                               const char* format,
139
                               Args&&... args) {
140



















1411255
  if (!UNLIKELY(list->enabled(cat))) return;
141
1021
  FPrintF(stderr, format, std::forward<Args>(args)...);
142
}
143
144
inline void FORCE_INLINE Debug(EnabledDebugList* list,
145
                               DebugCategory cat,
146
                               const char* message) {
147



7324
  if (!UNLIKELY(list->enabled(cat))) return;
148
77
  FPrintF(stderr, "%s", message);
149
}
150
151
template <typename... Args>
152
inline void FORCE_INLINE
153
Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args) {
154
84365
  Debug(env->enabled_debug_list(), cat, format, std::forward<Args>(args)...);
155
}
156
157
inline void FORCE_INLINE Debug(Environment* env,
158
                               DebugCategory cat,
159
                               const char* message) {
160
13026
  Debug(env->enabled_debug_list(), cat, message);
161
}
162
163
template <typename... Args>
164
250
inline void Debug(Environment* env,
165
                  DebugCategory cat,
166
                  const std::string& format,
167
                  Args&&... args) {
168
250
  Debug(env->enabled_debug_list(),
169
        cat,
170
        format.c_str(),
171
        std::forward<Args>(args)...);
172
}
173
174
// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
175
// the FORCE_INLINE flag on them doesn't apply to the contents of this function
176
// as well.
177
// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing
178
// this function for speed and it should rather focus on keeping it out of
179
// hot code paths. In particular, we want to keep the string concatenating code
180
// out of the function containing the original `Debug()` call.
181
template <typename... Args>
182
250
void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
183
                                               const char* format,
184
                                               Args&&... args) {
185
664
  Debug(async_wrap->env(),
186
250
        static_cast<DebugCategory>(async_wrap->provider_type()),
187
250
        async_wrap->diagnostic_name() + " " + format + "\n",
188
        std::forward<Args>(args)...);
189
}
190
191
template <typename... Args>
192
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
193
                               const char* format,
194
                               Args&&... args) {
195
  DCHECK_NOT_NULL(async_wrap);
196
1312091
  DebugCategory cat = static_cast<DebugCategory>(async_wrap->provider_type());
197




































2626142
  if (!UNLIKELY(async_wrap->env()->enabled_debug_list()->enabled(cat))) return;
198
125
  UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...);
199
}
200
201
template <typename... Args>
202
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
203
                               const std::string& format,
204
                               Args&&... args) {
205
  Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
206
}
207
208
namespace per_process {
209
210
template <typename... Args>
211
inline void FORCE_INLINE Debug(DebugCategory cat,
212
                               const char* format,
213
                               Args&&... args) {
214
1326804
  Debug(&enabled_debug_list, cat, format, std::forward<Args>(args)...);
215
}
216
217
inline void FORCE_INLINE Debug(DebugCategory cat, const char* message) {
218
12
  Debug(&enabled_debug_list, cat, message);
219
}
220
221
}  // namespace per_process
222
}  // namespace node
223
224
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
225
226
#endif  // SRC_DEBUG_UTILS_INL_H_