Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/debug_utils-inl.h
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 #include "util-inl.h" 9 10 #include <type_traits> 11 12 namespace node { 13 14 template <typename T> 15 concept StringViewConvertible = requires(T a) { 16 { 17 a.ToStringView() 18 } -> std::convertible_to<std::string_view>; 19 }; 20 template <typename T> 21 concept StringConvertible = requires(T a) { 22 { 23 a.ToString() 24 } -> std::convertible_to<std::string>; 25 }; 26 // For std::filesystem::path and similar types 27 template <typename T> 28 concept StringConvertibleFSPathLike = requires(T a) { 29 { 30 a.string() 31 } -> std::convertible_to<std::string>; 32 }; 33 34 struct ToStringHelper { 35 template <typename T> 36 requires(StringConvertible<T>) && (!StringViewConvertible<T>) 37 static std::string Convert(const T& value) { 38 return value.ToString(); 39 } 40 template <typename T> 41 requires(StringConvertibleFSPathLike<T>) && (!StringViewConvertible<T>) && 42 (!StringConvertible<T>) 43 static std::string Convert(const T& value) { 44 return value.string(); 45 } 46 template <typename T> 47 requires StringViewConvertible<T> 48 static std::string_view Convert(const T& value) { 49 return value.ToStringView(); 50 } 51 52 template <typename T, 53 typename test_for_number = typename std:: 54 enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>, bool>, 55 typename dummy = bool> 56 static std::string Convert(const T& value) { 57 return std::to_string(value); 58 } 59 static std::string_view Convert(const char* value) { 60 return value != nullptr ? value : "(null)"; 61 } 62 static std::string Convert(const std::string& value) { return value; } 63 static std::string_view Convert(std::string_view value) { return value; } 64 static std::string Convert(bool value) { return value ? "true" : "false"; } 65 template <unsigned BASE_BITS, 66 typename T, 67 typename = std::enable_if_t<std::is_integral_v<T>>> 68 static std::string BaseConvert(const T& value) { 69 auto v = static_cast<uint64_t>(value); 70 char ret[3 * sizeof(T)]; 71 char* ptr = ret + 3 * sizeof(T) - 1; 72 *ptr = '\0'; 73 const char* digits = "0123456789abcdef"; 74 do { 75 unsigned digit = v & ((1 << BASE_BITS) - 1); 76 *--ptr = (BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]); 77 } while ((v >>= BASE_BITS) != 0); 78 return ptr; 79 } 80 template <unsigned BASE_BITS, 81 typename T, 82 typename = std::enable_if_t<!std::is_integral_v<T>>> 83 static auto BaseConvert(T&& value) { 84 return Convert(std::forward<T>(value)); 85 } 86 }; 87 88 template <typename T> 89 auto ToStringOrStringView(const T& value) { 90 return ToStringHelper::Convert(value); 91 } 92 93 template <typename T> 94 std::string ToString(const T& value) { 95 return std::string(ToStringOrStringView(value)); 96 } 97 98 template <unsigned BASE_BITS, typename T> 99 auto ToBaseString(const T& value) { 100 return ToStringHelper::BaseConvert<BASE_BITS>(value); 101 } 102 103 inline std::string SPrintFImpl(std::string_view format) { 104 auto offset = format.find('%'); 105 if (offset == std::string_view::npos) return std::string(format); 106 CHECK_LT(offset + 1, format.size()); 107 CHECK_EQ(format[offset + 1], 108 '%'); // Only '%%' allowed when there are no arguments. 109 110 return std::string(format.substr(0, offset + 1)) + 111 SPrintFImpl(format.substr(offset + 2)); 112 } 113 114 template <typename Arg, typename... Args> 115 std::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string) 116 std::string_view format, 117 Arg&& arg, 118 Args&&... args) { 119 auto offset = format.find('%'); 120 CHECK_NE(offset, std::string_view::npos); // If you hit this, you passed in 121 // too many arguments. 122 std::string ret(format.substr(0, offset)); 123 // Ignore long / size_t modifiers 124 while (++offset < format.size() && 125 (format[offset] == 'l' || format[offset] == 'z')) { 126 } 127 switch (offset == format.size() ? '\0' : format[offset]) { 128 case '%': { 129 return ret + '%' + 130 SPrintFImpl(format.substr(offset + 1), 131 std::forward<Arg>(arg), 132 std::forward<Args>(args)...); 133 } 134 default: { 135 return ret + '%' + 136 SPrintFImpl(format.substr(offset), 137 std::forward<Arg>(arg), 138 std::forward<Args>(args)...); 139 } 140 case 'd': 141 case 'i': 142 case 'u': 143 case 's': 144 ret += ToStringOrStringView(arg); 145 break; 146 case 'o': 147 ret += ToBaseString<3>(arg); 148 break; 149 case 'x': 150 ret += ToBaseString<4>(arg); 151 break; 152 case 'X': 153 ret += node::ToUpper(ToBaseString<4>(arg)); 154 break; 155 case 'p': { 156 CHECK(std::is_pointer_v<typename std::remove_reference_t<Arg>>); 157 char out[20]; 158 int n = snprintf( 159 out, sizeof(out), "%p", *reinterpret_cast<const void* const*>(&arg)); 160 CHECK_GE(n, 0); 161 ret += out; 162 break; 163 } 164 } 165 return ret + 166 SPrintFImpl(format.substr(offset + 1), std::forward<Args>(args)...); 167 } 168 169 template <typename... Args> 170 std::string COLD_NOINLINE SPrintF( // NOLINT(runtime/string) 171 std::string_view format, 172 Args&&... args) { 173 return SPrintFImpl(format, std::forward<Args>(args)...); 174 } 175 176 template <typename... Args> 177 void COLD_NOINLINE FPrintF(FILE* file, 178 std::string_view format, 179 Args&&... args) { 180 FWrite(file, SPrintF(format, std::forward<Args>(args)...)); 181 } 182 183 template <typename... Args> 184 inline void FORCE_INLINE Debug(EnabledDebugList* list, 185 DebugCategory cat, 186 const char* format, 187 Args&&... args) { 188 if (!list->enabled(cat)) [[unlikely]] 189 return; 190 FPrintF(stderr, format, std::forward<Args>(args)...); 191 } 192 193 inline void FORCE_INLINE Debug(EnabledDebugList* list, 194 DebugCategory cat, 195 const char* message) { 196 if (!list->enabled(cat)) [[unlikely]] 197 return; 198 FPrintF(stderr, "%s", message); 199 } 200 201 template <typename... Args> 202 inline void FORCE_INLINE 203 Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args) { 204 Debug(env->enabled_debug_list(), cat, format, std::forward<Args>(args)...); 205 } 206 207 inline void FORCE_INLINE Debug(Environment* env, 208 DebugCategory cat, 209 const char* message) { 210 Debug(env->enabled_debug_list(), cat, message); 211 } 212 213 template <typename... Args> 214 inline void Debug(Environment* env, 215 DebugCategory cat, 216 const std::string& format, 217 Args&&... args) { 218 Debug(env->enabled_debug_list(), 219 cat, 220 format.c_str(), 221 std::forward<Args>(args)...); 222 } 223 224 // Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that 225 // the FORCE_INLINE flag on them doesn't apply to the contents of this function 226 // as well. 227 // We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing 228 // this function for speed and it should rather focus on keeping it out of 229 // hot code paths. In particular, we want to keep the string concatenating code 230 // out of the function containing the original `Debug()` call. 231 template <typename... Args> 232 void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap, 233 const char* format, 234 Args&&... args) { 235 Debug(async_wrap->env(), 236 static_cast<DebugCategory>(async_wrap->provider_type()), 237 async_wrap->diagnostic_name() + " " + format + "\n", 238 std::forward<Args>(args)...); 239 } 240 241 template <typename... Args> 242 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, 243 const char* format, 244 Args&&... args) { 245 DCHECK_NOT_NULL(async_wrap); 246 if (auto cat = static_cast<DebugCategory>(async_wrap->provider_type()); 247 !async_wrap->env()->enabled_debug_list()->enabled(cat)) [[unlikely]] { 248 return; 249 } 250 UnconditionalAsyncWrapDebug(async_wrap, format, std::forward<Args>(args)...); 251 } 252 253 template <typename... Args> 254 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, 255 const std::string& format, 256 Args&&... args) { 257 Debug(async_wrap, format.c_str(), std::forward<Args>(args)...); 258 } 259 260 namespace per_process { 261 262 template <typename... Args> 263 inline void FORCE_INLINE Debug(DebugCategory cat, 264 const char* format, 265 Args&&... args) { 266 Debug(&enabled_debug_list, cat, format, std::forward<Args>(args)...); 267 } 268 269 inline void FORCE_INLINE Debug(DebugCategory cat, const char* message) { 270 Debug(&enabled_debug_list, cat, message); 271 } 272 273 } // namespace per_process 274 } // namespace node 275 276 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 277 278 #endif // SRC_DEBUG_UTILS_INL_H_