Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/blob_serializer_deserializer-inl.h
1 #ifndef SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_ 2 #define SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 #include "blob_serializer_deserializer.h" 7 8 #include <ostream> 9 #include <sstream> 10 #include <string> 11 #include <type_traits> 12 #include <utility> 13 14 #include "debug_utils-inl.h" 15 16 // This is related to the blob that is used in snapshots and single executable 17 // applications and has nothing to do with `node_blob.h`. 18 19 namespace node { 20 21 struct EnvSerializeInfo; 22 struct PropInfo; 23 struct RealmSerializeInfo; 24 25 namespace builtins { 26 struct CodeCacheInfo; 27 } // namespace builtins 28 29 // These operator<< overload declarations are needed because 30 // BlobSerializerDeserializer::ToStr() uses these. 31 32 std::ostream& operator<<(std::ostream& output, 33 const builtins::CodeCacheInfo& info); 34 35 std::ostream& operator<<(std::ostream& output, 36 const std::vector<builtins::CodeCacheInfo>& vec); 37 38 std::ostream& operator<<(std::ostream& output, const std::vector<uint8_t>& vec); 39 40 std::ostream& operator<<(std::ostream& output, 41 const std::vector<PropInfo>& vec); 42 43 std::ostream& operator<<(std::ostream& output, const PropInfo& info); 44 45 std::ostream& operator<<(std::ostream& output, 46 const std::vector<std::string>& vec); 47 48 std::ostream& operator<<(std::ostream& output, const RealmSerializeInfo& i); 49 50 std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i); 51 52 template <typename... Args> 53 void BlobSerializerDeserializer::Debug(const char* format, 54 Args&&... args) const { 55 if (is_debug) { 56 FPrintF(stderr, format, std::forward<Args>(args)...); 57 } 58 } 59 60 template <typename T> 61 std::string BlobSerializerDeserializer::ToStr(const T& arg) const { 62 std::stringstream ss; 63 ss << arg; 64 return ss.str(); 65 } 66 67 template <typename T> 68 std::string BlobSerializerDeserializer::GetName() const { 69 #define TYPE_LIST(V) \ 70 V(builtins::CodeCacheInfo) \ 71 V(PropInfo) \ 72 V(std::string) 73 74 #define V(TypeName) \ 75 if constexpr (std::is_same_v<T, TypeName>) { \ 76 return #TypeName; \ 77 } else // NOLINT(readability/braces) 78 TYPE_LIST(V) 79 #undef V 80 81 if constexpr (std::is_arithmetic_v<T>) { 82 return (std::is_unsigned_v<T> ? "uint" 83 : std::is_integral_v<T> ? "int" 84 : "float") + 85 std::to_string(sizeof(T) * 8) + "_t"; 86 } 87 return ""; 88 } 89 90 // Helper for reading numeric types. 91 template <typename Impl> 92 template <typename T> 93 T BlobDeserializer<Impl>::ReadArithmetic() { 94 static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); 95 T result; 96 ReadArithmetic(&result, 1); 97 return result; 98 } 99 100 // Layout of vectors: 101 // [ 4/8 bytes ] count 102 // [ ... ] contents (count * size of individual elements) 103 template <typename Impl> 104 template <typename T> 105 std::vector<T> BlobDeserializer<Impl>::ReadVector() { 106 if (is_debug) { 107 std::string name = GetName<T>(); 108 Debug("\nReadVector<%s>()(%d-byte)\n", name.c_str(), sizeof(T)); 109 } 110 size_t count = static_cast<size_t>(ReadArithmetic<size_t>()); 111 if (count == 0) { 112 return std::vector<T>(); 113 } 114 if (is_debug) { 115 Debug("Reading %d vector elements...\n", count); 116 } 117 std::vector<T> result; 118 if constexpr (std::is_arithmetic_v<T>) { 119 result = ReadArithmeticVector<T>(count); 120 } else { 121 result = ReadNonArithmeticVector<T>(count); 122 } 123 if (is_debug) { 124 std::string str = std::is_arithmetic_v<T> ? "" : ToStr(result); 125 std::string name = GetName<T>(); 126 Debug("ReadVector<%s>() read %s\n", name.c_str(), str.c_str()); 127 } 128 return result; 129 } 130 131 template <typename Impl> 132 std::string BlobDeserializer<Impl>::ReadString() { 133 std::string_view view = ReadStringView(StringLogMode::kAddressAndContent); 134 return std::string(view); 135 } 136 137 template <typename Impl> 138 std::string_view BlobDeserializer<Impl>::ReadStringView(StringLogMode mode) { 139 size_t length = ReadArithmetic<size_t>(); 140 Debug("ReadStringView(), length=%zu: ", length); 141 142 if (length == 0) { 143 Debug("ReadStringView() read an empty view\n"); 144 return std::string_view(); 145 } 146 147 std::string_view result(sink.data() + read_total, length); 148 Debug("%p, read %zu bytes", result.data(), result.size()); 149 if (mode == StringLogMode::kAddressAndContent) { 150 Debug(", content:%s%s", length > 32 ? "\n" : " ", result); 151 } 152 Debug("\n"); 153 154 read_total += length; 155 return result; 156 } 157 158 // Helper for reading an array of numeric types. 159 template <typename Impl> 160 template <typename T> 161 void BlobDeserializer<Impl>::ReadArithmetic(T* out, size_t count) { 162 static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); 163 DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. 164 if (is_debug) { 165 std::string name = GetName<T>(); 166 Debug("Read<%s>()(%d-byte), count=%d: ", name.c_str(), sizeof(T), count); 167 } 168 169 size_t size = sizeof(T) * count; 170 memcpy(out, sink.data() + read_total, size); 171 172 if (is_debug) { 173 std::string str = 174 "{ " + std::to_string(out[0]) + (count > 1 ? ", ... }" : " }"); 175 Debug("%s, read %zu bytes\n", str.c_str(), size); 176 } 177 read_total += size; 178 } 179 180 // Helper for reading numeric vectors. 181 template <typename Impl> 182 template <typename Number> 183 std::vector<Number> BlobDeserializer<Impl>::ReadArithmeticVector(size_t count) { 184 static_assert(std::is_arithmetic_v<Number>, "Not an arithmetic type"); 185 DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. 186 std::vector<Number> result(count); 187 ReadArithmetic(result.data(), count); 188 return result; 189 } 190 191 // Helper for reading non-numeric vectors. 192 template <typename Impl> 193 template <typename T> 194 std::vector<T> BlobDeserializer<Impl>::ReadNonArithmeticVector(size_t count) { 195 static_assert(!std::is_arithmetic_v<T>, "Arithmetic type"); 196 DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. 197 std::vector<T> result; 198 result.reserve(count); 199 bool original_is_debug = is_debug; 200 is_debug = original_is_debug && !std::is_same_v<T, std::string>; 201 for (size_t i = 0; i < count; ++i) { 202 if (is_debug) { 203 Debug("\n[%d] ", i); 204 } 205 result.push_back(ReadElement<T>()); 206 } 207 is_debug = original_is_debug; 208 209 return result; 210 } 211 212 template <typename Impl> 213 template <typename T> 214 T BlobDeserializer<Impl>::ReadElement() { 215 if constexpr (std::is_arithmetic_v<T>) { 216 return ReadArithmetic<T>(); 217 } else if constexpr (std::is_same_v<T, std::string>) { 218 return ReadString(); 219 } else { 220 return impl()->template Read<T>(); 221 } 222 } 223 224 // Helper for writing numeric types. 225 template <typename Impl> 226 template <typename T> 227 size_t BlobSerializer<Impl>::WriteArithmetic(const T& data) { 228 static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); 229 return WriteArithmetic(&data, 1); 230 } 231 232 // Layout of vectors: 233 // [ 4/8 bytes ] count 234 // [ ... ] contents (count * size of individual elements) 235 template <typename Impl> 236 template <typename T> 237 size_t BlobSerializer<Impl>::WriteVector(const std::vector<T>& data) { 238 if (is_debug) { 239 std::string str = std::is_arithmetic_v<T> ? "" : ToStr(data); 240 std::string name = GetName<T>(); 241 Debug("\nAt 0x%x: WriteVector<%s>() (%d-byte), count=%d: %s\n", 242 sink.size(), 243 name.c_str(), 244 sizeof(T), 245 data.size(), 246 str.c_str()); 247 } 248 249 size_t written_total = WriteArithmetic<size_t>(data.size()); 250 if (data.empty()) { 251 return written_total; 252 } 253 254 if constexpr (std::is_arithmetic_v<T>) { 255 written_total += WriteArithmeticVector<T>(data); 256 } else { 257 written_total += WriteNonArithmeticVector<T>(data); 258 } 259 260 if (is_debug) { 261 std::string name = GetName<T>(); 262 Debug("WriteVector<%s>() wrote %d bytes\n", name.c_str(), written_total); 263 } 264 265 return written_total; 266 } 267 268 // The layout of a written string: 269 // [ 4/8 bytes ] length 270 // [ |length| bytes ] contents 271 template <typename Impl> 272 size_t BlobSerializer<Impl>::WriteStringView(std::string_view data, 273 StringLogMode mode) { 274 Debug("At 0x%x: WriteStringView(), length=%zu: %p\n", 275 sink.size(), 276 data.size(), 277 data.data()); 278 size_t written_total = WriteArithmetic<size_t>(data.size()); 279 280 size_t length = data.size(); 281 if (length == 0) { 282 Debug("WriteStringView() wrote an empty view\n"); 283 return written_total; 284 } 285 sink.insert(sink.end(), data.data(), data.data() + length); 286 written_total += length; 287 288 Debug("WriteStringView() wrote %zu bytes\n", written_total); 289 if (mode == StringLogMode::kAddressAndContent) { 290 Debug("%s", data); 291 } 292 293 return written_total; 294 } 295 296 template <typename Impl> 297 size_t BlobSerializer<Impl>::WriteString(const std::string& data) { 298 return WriteStringView(data, StringLogMode::kAddressAndContent); 299 } 300 301 static size_t kPreviewCount = 16; 302 303 // Helper for writing an array of numeric types. 304 template <typename Impl> 305 template <typename T> 306 size_t BlobSerializer<Impl>::WriteArithmetic(const T* data, size_t count) { 307 static_assert(std::is_arithmetic_v<T>, "Arithmetic type"); 308 DCHECK_GT(count, 0); // Should not write contents for vectors of size 0. 309 if (is_debug) { 310 size_t preview_count = count < kPreviewCount ? count : kPreviewCount; 311 std::string str = "{ "; 312 for (size_t i = 0; i < preview_count; ++i) { 313 str += (std::to_string(data[i]) + ","); 314 } 315 if (count > preview_count) { 316 str += "..."; 317 } 318 str += "}"; 319 std::string name = GetName<T>(); 320 Debug("At 0x%x: Write<%s>() (%zu-byte), count=%zu: %s", 321 sink.size(), 322 name.c_str(), 323 sizeof(T), 324 count, 325 str.c_str()); 326 } 327 328 size_t size = sizeof(T) * count; 329 const char* pos = reinterpret_cast<const char*>(data); 330 sink.insert(sink.end(), pos, pos + size); 331 332 if (is_debug) { 333 Debug(", wrote %zu bytes\n", size); 334 } 335 return size; 336 } 337 338 // Helper for writing numeric vectors. 339 template <typename Impl> 340 template <typename Number> 341 size_t BlobSerializer<Impl>::WriteArithmeticVector( 342 const std::vector<Number>& data) { 343 static_assert(std::is_arithmetic_v<Number>, "Arithmetic type"); 344 return WriteArithmetic(data.data(), data.size()); 345 } 346 347 // Helper for writing non-numeric vectors. 348 template <typename Impl> 349 template <typename T> 350 size_t BlobSerializer<Impl>::WriteNonArithmeticVector( 351 const std::vector<T>& data) { 352 static_assert(!std::is_arithmetic_v<T>, "Arithmetic type"); 353 DCHECK_GT(data.size(), 354 0); // Should not write contents for vectors of size 0. 355 size_t written_total = 0; 356 bool original_is_debug = is_debug; 357 is_debug = original_is_debug && !std::is_same_v<T, std::string>; 358 for (size_t i = 0; i < data.size(); ++i) { 359 if (is_debug) { 360 Debug("\n[%d] ", i); 361 } 362 written_total += WriteElement<T>(data[i]); 363 } 364 is_debug = original_is_debug; 365 366 return written_total; 367 } 368 369 template <typename Impl> 370 template <typename T> 371 size_t BlobSerializer<Impl>::WriteElement(const T& data) { 372 if constexpr (std::is_arithmetic_v<T>) { 373 return WriteArithmetic<T>(data); 374 } else if constexpr (std::is_same_v<T, std::string>) { 375 return WriteString(data); 376 } else { 377 return impl()->template Write<T>(data); 378 } 379 } 380 381 } // namespace node 382 383 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 384 385 #endif // SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_