• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   static std::string Convert(
16       const T& value,
17       std::string(T::* to_string)() const = &T::ToString) {
18     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>
ConvertToStringHelper24   static std::string Convert(const T& value) { return std::to_string(value); }
ConvertToStringHelper25   static std::string Convert(const char* value) {
26     return value != nullptr ? value : "(null)";
27   }
ConvertToStringHelper28   static std::string Convert(const std::string& value) { return value; }
ConvertToStringHelper29   static std::string Convert(bool value) { return value ? "true" : "false"; }
30   template <unsigned BASE_BITS,
31             typename T,
32             typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
BaseConvertToStringHelper33   static std::string BaseConvert(const T& value) {
34     auto v = static_cast<uint64_t>(value);
35     char ret[3 * sizeof(T)];
36     char* ptr = ret + 3 * sizeof(T) - 1;
37     *ptr = '\0';
38     const char* digits = "0123456789abcdef";
39     do {
40       unsigned digit = v & ((1 << BASE_BITS) - 1);
41       *--ptr =
42           (BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]);
43     } while ((v >>= BASE_BITS) != 0);
44     return ptr;
45   }
46   template <unsigned BASE_BITS,
47             typename T,
48             typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
BaseConvertToStringHelper49   static std::string BaseConvert(T value) {
50     return Convert(std::forward<T>(value));
51   }
52 };
53 
54 template <typename T>
ToString(const T & value)55 std::string ToString(const T& value) {
56   return ToStringHelper::Convert(value);
57 }
58 
59 template <unsigned BASE_BITS, typename T>
ToBaseString(const T & value)60 std::string ToBaseString(const T& value) {
61   return ToStringHelper::BaseConvert<BASE_BITS>(value);
62 }
63 
SPrintFImpl(const char * format)64 inline std::string SPrintFImpl(const char* format) {
65   const char* p = strchr(format, '%');
66   if (LIKELY(p == nullptr)) return format;
67   CHECK_EQ(p[1], '%');  // Only '%%' allowed when there are no arguments.
68 
69   return std::string(format, p + 1) + SPrintFImpl(p + 2);
70 }
71 
72 template <typename Arg, typename... Args>
SPrintFImpl(const char * format,Arg && arg,Args &&...args)73 std::string COLD_NOINLINE SPrintFImpl(  // NOLINT(runtime/string)
74     const char* format, Arg&& arg, Args&&... args) {
75   const char* p = strchr(format, '%');
76   CHECK_NOT_NULL(p);  // If you hit this, you passed in too many arguments.
77   std::string ret(format, p);
78   // Ignore long / size_t modifiers
79   while (strchr("lz", *++p) != nullptr) {}
80   switch (*p) {
81     case '%': {
82       return ret + '%' + SPrintFImpl(p + 1,
83                                      std::forward<Arg>(arg),
84                                      std::forward<Args>(args)...);
85     }
86     default: {
87       return ret + '%' + SPrintFImpl(p,
88                                      std::forward<Arg>(arg),
89                                      std::forward<Args>(args)...);
90     }
91     case 'd':
92     case 'i':
93     case 'u':
94     case 's':
95       ret += ToString(arg);
96       break;
97     case 'o':
98       ret += ToBaseString<3>(arg);
99       break;
100     case 'x':
101       ret += ToBaseString<4>(arg);
102       break;
103     case 'X':
104       ret += node::ToUpper(ToBaseString<4>(arg));
105       break;
106     case 'p': {
107       CHECK(std::is_pointer<typename std::remove_reference<Arg>::type>::value);
108       char out[20];
109       int n = snprintf(out,
110                        sizeof(out),
111                        "%p",
112                        *reinterpret_cast<const void* const*>(&arg));
113       CHECK_GE(n, 0);
114       ret += out;
115       break;
116     }
117   }
118   return ret + SPrintFImpl(p + 1, std::forward<Args>(args)...);
119 }
120 
121 template <typename... Args>
SPrintF(const char * format,Args &&...args)122 std::string COLD_NOINLINE SPrintF(  // NOLINT(runtime/string)
123     const char* format, Args&&... args) {
124   return SPrintFImpl(format, std::forward<Args>(args)...);
125 }
126 
127 template <typename... Args>
FPrintF(FILE * file,const char * format,Args &&...args)128 void COLD_NOINLINE FPrintF(FILE* file, const char* format, Args&&... args) {
129   FWrite(file, SPrintF(format, std::forward<Args>(args)...));
130 }
131 
132 template <typename... Args>
Debug(EnabledDebugList * list,DebugCategory cat,const char * format,Args &&...args)133 inline void FORCE_INLINE Debug(EnabledDebugList* list,
134                                DebugCategory cat,
135                                const char* format,
136                                Args&&... args) {
137   if (!UNLIKELY(list->enabled(cat))) return;
138   FPrintF(stderr, format, std::forward<Args>(args)...);
139 }
140 
Debug(EnabledDebugList * list,DebugCategory cat,const char * message)141 inline void FORCE_INLINE Debug(EnabledDebugList* list,
142                                DebugCategory cat,
143                                const char* message) {
144   if (!UNLIKELY(list->enabled(cat))) return;
145   FPrintF(stderr, "%s", message);
146 }
147 
148 template <typename... Args>
149 inline void FORCE_INLINE
Debug(Environment * env,DebugCategory cat,const char * format,Args &&...args)150 Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args) {
151   Debug(env->enabled_debug_list(), cat, format, std::forward<Args>(args)...);
152 }
153 
Debug(Environment * env,DebugCategory cat,const char * message)154 inline void FORCE_INLINE Debug(Environment* env,
155                                DebugCategory cat,
156                                const char* message) {
157   Debug(env->enabled_debug_list(), cat, message);
158 }
159 
160 template <typename... Args>
Debug(Environment * env,DebugCategory cat,const std::string & format,Args &&...args)161 inline void Debug(Environment* env,
162                   DebugCategory cat,
163                   const std::string& format,
164                   Args&&... args) {
165   Debug(env->enabled_debug_list(),
166         cat,
167         format.c_str(),
168         std::forward<Args>(args)...);
169 }
170 
171 // Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
172 // the FORCE_INLINE flag on them doesn't apply to the contents of this function
173 // as well.
174 // We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing
175 // this function for speed and it should rather focus on keeping it out of
176 // hot code paths. In particular, we want to keep the string concatenating code
177 // out of the function containing the original `Debug()` call.
178 template <typename... Args>
UnconditionalAsyncWrapDebug(AsyncWrap * async_wrap,const char * format,Args &&...args)179 void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
180                                                const char* format,
181                                                Args&&... args) {
182   Debug(async_wrap->env(),
183         static_cast<DebugCategory>(async_wrap->provider_type()),
184         async_wrap->diagnostic_name() + " " + format + "\n",
185         std::forward<Args>(args)...);
186 }
187 
188 template <typename... Args>
Debug(AsyncWrap * async_wrap,const char * format,Args &&...args)189 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
190                                const char* format,
191                                Args&&... args) {
192   DCHECK_NOT_NULL(async_wrap);
193   DebugCategory cat = static_cast<DebugCategory>(async_wrap->provider_type());
194   if (!UNLIKELY(async_wrap->env()->enabled_debug_list()->enabled(cat))) return;
195   UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...);
196 }
197 
198 template <typename... Args>
Debug(AsyncWrap * async_wrap,const std::string & format,Args &&...args)199 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
200                                const std::string& format,
201                                Args&&... args) {
202   Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
203 }
204 
205 namespace per_process {
206 
207 template <typename... Args>
Debug(DebugCategory cat,const char * format,Args &&...args)208 inline void FORCE_INLINE Debug(DebugCategory cat,
209                                const char* format,
210                                Args&&... args) {
211   Debug(&enabled_debug_list, cat, format, std::forward<Args>(args)...);
212 }
213 
Debug(DebugCategory cat,const char * message)214 inline void FORCE_INLINE Debug(DebugCategory cat, const char* message) {
215   Debug(&enabled_debug_list, cat, message);
216 }
217 
218 }  // namespace per_process
219 }  // namespace node
220 
221 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
222 
223 #endif  // SRC_DEBUG_UTILS_INL_H_
224