-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
src: move BlobSerializerDeserializer
to a separate header file
#47933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
RaisinTen
wants to merge
3
commits into
nodejs:main
from
RaisinTen:move-BlobSerializerDeserializer-to-separate-header
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,359 @@ | ||
#ifndef SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_ | ||
#define SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_ | ||
|
||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | ||
|
||
#include "blob_serializer_deserializer.h" | ||
|
||
#include <ostream> | ||
#include <sstream> | ||
#include <string> | ||
#include <type_traits> | ||
#include <utility> | ||
|
||
#include "debug_utils-inl.h" | ||
|
||
// This is related to the blob that is used in snapshots and has nothing to do | ||
// with `node_blob.h`. | ||
|
||
namespace node { | ||
|
||
struct EnvSerializeInfo; | ||
struct PropInfo; | ||
struct RealmSerializeInfo; | ||
|
||
namespace builtins { | ||
struct CodeCacheInfo; | ||
} // namespace builtins | ||
|
||
// These operator<< overload declarations are needed because | ||
// BlobSerializerDeserializer::ToStr() uses these. | ||
|
||
std::ostream& operator<<(std::ostream& output, | ||
const builtins::CodeCacheInfo& info); | ||
|
||
std::ostream& operator<<(std::ostream& output, | ||
const std::vector<builtins::CodeCacheInfo>& vec); | ||
|
||
std::ostream& operator<<(std::ostream& output, const std::vector<uint8_t>& vec); | ||
|
||
std::ostream& operator<<(std::ostream& output, | ||
const std::vector<PropInfo>& vec); | ||
|
||
std::ostream& operator<<(std::ostream& output, const PropInfo& info); | ||
|
||
std::ostream& operator<<(std::ostream& output, | ||
const std::vector<std::string>& vec); | ||
|
||
std::ostream& operator<<(std::ostream& output, const RealmSerializeInfo& i); | ||
|
||
std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i); | ||
|
||
template <typename... Args> | ||
void BlobSerializerDeserializer::Debug(const char* format, | ||
Args&&... args) const { | ||
if (is_debug) { | ||
FPrintF(stderr, format, std::forward<Args>(args)...); | ||
} | ||
} | ||
|
||
template <typename T> | ||
std::string BlobSerializerDeserializer::ToStr(const T& arg) const { | ||
std::stringstream ss; | ||
ss << arg; | ||
return ss.str(); | ||
} | ||
|
||
template <typename T> | ||
std::string BlobSerializerDeserializer::GetName() const { | ||
#define TYPE_LIST(V) \ | ||
V(builtins::CodeCacheInfo) \ | ||
V(PropInfo) \ | ||
V(std::string) | ||
|
||
#define V(TypeName) \ | ||
if constexpr (std::is_same_v<T, TypeName>) { \ | ||
return #TypeName; \ | ||
} else // NOLINT(readability/braces) | ||
TYPE_LIST(V) | ||
#undef V | ||
|
||
if constexpr (std::is_arithmetic_v<T>) { | ||
return (std::is_unsigned_v<T> ? "uint" | ||
: std::is_integral_v<T> ? "int" | ||
: "float") + | ||
std::to_string(sizeof(T) * 8) + "_t"; | ||
} | ||
return ""; | ||
} | ||
|
||
// Helper for reading numeric types. | ||
template <typename Impl> | ||
template <typename T> | ||
T BlobDeserializer<Impl>::ReadArithmetic() { | ||
static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); | ||
T result; | ||
ReadArithmetic(&result, 1); | ||
return result; | ||
} | ||
|
||
// Layout of vectors: | ||
// [ 4/8 bytes ] count | ||
// [ ... ] contents (count * size of individual elements) | ||
template <typename Impl> | ||
template <typename T> | ||
std::vector<T> BlobDeserializer<Impl>::ReadVector() { | ||
if (is_debug) { | ||
std::string name = GetName<T>(); | ||
Debug("\nReadVector<%s>()(%d-byte)\n", name.c_str(), sizeof(T)); | ||
} | ||
size_t count = static_cast<size_t>(ReadArithmetic<size_t>()); | ||
if (count == 0) { | ||
return std::vector<T>(); | ||
} | ||
if (is_debug) { | ||
Debug("Reading %d vector elements...\n", count); | ||
} | ||
std::vector<T> result; | ||
if constexpr (std::is_arithmetic_v<T>) { | ||
result = ReadArithmeticVector<T>(count); | ||
} else { | ||
result = ReadNonArithmeticVector<T>(count); | ||
} | ||
if (is_debug) { | ||
std::string str = std::is_arithmetic_v<T> ? "" : ToStr(result); | ||
std::string name = GetName<T>(); | ||
Debug("ReadVector<%s>() read %s\n", name.c_str(), str.c_str()); | ||
} | ||
return result; | ||
} | ||
|
||
template <typename Impl> | ||
std::string BlobDeserializer<Impl>::ReadString() { | ||
size_t length = ReadArithmetic<size_t>(); | ||
|
||
if (is_debug) { | ||
Debug("ReadString(), length=%d: ", length); | ||
} | ||
|
||
CHECK_GT(length, 0); // There should be no empty strings. | ||
MallocedBuffer<char> buf(length + 1); | ||
memcpy(buf.data, sink.data() + read_total, length + 1); | ||
std::string result(buf.data, length); // This creates a copy of buf.data. | ||
|
||
if (is_debug) { | ||
Debug("\"%s\", read %zu bytes\n", result.c_str(), length + 1); | ||
} | ||
|
||
read_total += length + 1; | ||
return result; | ||
} | ||
|
||
// Helper for reading an array of numeric types. | ||
template <typename Impl> | ||
template <typename T> | ||
void BlobDeserializer<Impl>::ReadArithmetic(T* out, size_t count) { | ||
static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); | ||
DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. | ||
if (is_debug) { | ||
std::string name = GetName<T>(); | ||
Debug("Read<%s>()(%d-byte), count=%d: ", name.c_str(), sizeof(T), count); | ||
} | ||
|
||
size_t size = sizeof(T) * count; | ||
memcpy(out, sink.data() + read_total, size); | ||
|
||
if (is_debug) { | ||
std::string str = | ||
"{ " + std::to_string(out[0]) + (count > 1 ? ", ... }" : " }"); | ||
Debug("%s, read %zu bytes\n", str.c_str(), size); | ||
} | ||
read_total += size; | ||
} | ||
|
||
// Helper for reading numeric vectors. | ||
template <typename Impl> | ||
template <typename Number> | ||
std::vector<Number> BlobDeserializer<Impl>::ReadArithmeticVector(size_t count) { | ||
static_assert(std::is_arithmetic_v<Number>, "Not an arithmetic type"); | ||
DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. | ||
std::vector<Number> result(count); | ||
ReadArithmetic(result.data(), count); | ||
return result; | ||
} | ||
|
||
// Helper for reading non-numeric vectors. | ||
template <typename Impl> | ||
template <typename T> | ||
std::vector<T> BlobDeserializer<Impl>::ReadNonArithmeticVector(size_t count) { | ||
static_assert(!std::is_arithmetic_v<T>, "Arithmetic type"); | ||
DCHECK_GT(count, 0); // Should not read contents for vectors of size 0. | ||
std::vector<T> result; | ||
result.reserve(count); | ||
bool original_is_debug = is_debug; | ||
is_debug = original_is_debug && !std::is_same_v<T, std::string>; | ||
for (size_t i = 0; i < count; ++i) { | ||
if (is_debug) { | ||
Debug("\n[%d] ", i); | ||
} | ||
result.push_back(ReadElement<T>()); | ||
} | ||
is_debug = original_is_debug; | ||
|
||
return result; | ||
} | ||
|
||
template <typename Impl> | ||
template <typename T> | ||
T BlobDeserializer<Impl>::ReadElement() { | ||
if constexpr (std::is_arithmetic_v<T>) { | ||
return ReadArithmetic<T>(); | ||
} else if constexpr (std::is_same_v<T, std::string>) { | ||
return ReadString(); | ||
} else { | ||
return impl()->template Read<T>(); | ||
} | ||
} | ||
|
||
// Helper for writing numeric types. | ||
template <typename Impl> | ||
template <typename T> | ||
size_t BlobSerializer<Impl>::WriteArithmetic(const T& data) { | ||
static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type"); | ||
return WriteArithmetic(&data, 1); | ||
} | ||
|
||
// Layout of vectors: | ||
// [ 4/8 bytes ] count | ||
// [ ... ] contents (count * size of individual elements) | ||
template <typename Impl> | ||
template <typename T> | ||
size_t BlobSerializer<Impl>::WriteVector(const std::vector<T>& data) { | ||
if (is_debug) { | ||
std::string str = std::is_arithmetic_v<T> ? "" : ToStr(data); | ||
std::string name = GetName<T>(); | ||
Debug("\nWriteVector<%s>() (%d-byte), count=%d: %s\n", | ||
name.c_str(), | ||
sizeof(T), | ||
data.size(), | ||
str.c_str()); | ||
} | ||
|
||
size_t written_total = WriteArithmetic<size_t>(data.size()); | ||
if (data.size() == 0) { | ||
return written_total; | ||
} | ||
|
||
if constexpr (std::is_arithmetic_v<T>) { | ||
written_total += WriteArithmeticVector<T>(data); | ||
} else { | ||
written_total += WriteNonArithmeticVector<T>(data); | ||
} | ||
|
||
if (is_debug) { | ||
std::string name = GetName<T>(); | ||
Debug("WriteVector<%s>() wrote %d bytes\n", name.c_str(), written_total); | ||
} | ||
|
||
return written_total; | ||
} | ||
|
||
// The layout of a written string: | ||
// [ 4/8 bytes ] length | ||
// [ |length| bytes ] contents | ||
template <typename Impl> | ||
size_t BlobSerializer<Impl>::WriteString(const std::string& data) { | ||
CHECK_GT(data.size(), 0); // No empty strings should be written. | ||
size_t written_total = WriteArithmetic<size_t>(data.size()); | ||
if (is_debug) { | ||
std::string str = ToStr(data); | ||
Debug("WriteString(), length=%zu: \"%s\"\n", data.size(), data.c_str()); | ||
} | ||
|
||
// Write the null-terminated string. | ||
size_t length = data.size() + 1; | ||
sink.insert(sink.end(), data.c_str(), data.c_str() + length); | ||
written_total += length; | ||
|
||
if (is_debug) { | ||
Debug("WriteString() wrote %zu bytes\n", written_total); | ||
} | ||
|
||
return written_total; | ||
} | ||
|
||
// Helper for writing an array of numeric types. | ||
template <typename Impl> | ||
template <typename T> | ||
size_t BlobSerializer<Impl>::WriteArithmetic(const T* data, size_t count) { | ||
static_assert(std::is_arithmetic_v<T>, "Arithmetic type"); | ||
DCHECK_GT(count, 0); // Should not write contents for vectors of size 0. | ||
if (is_debug) { | ||
std::string str = | ||
"{ " + std::to_string(data[0]) + (count > 1 ? ", ... }" : " }"); | ||
std::string name = GetName<T>(); | ||
Debug("Write<%s>() (%zu-byte), count=%zu: %s", | ||
name.c_str(), | ||
sizeof(T), | ||
count, | ||
str.c_str()); | ||
} | ||
|
||
size_t size = sizeof(T) * count; | ||
const char* pos = reinterpret_cast<const char*>(data); | ||
sink.insert(sink.end(), pos, pos + size); | ||
|
||
if (is_debug) { | ||
Debug(", wrote %zu bytes\n", size); | ||
} | ||
return size; | ||
} | ||
|
||
// Helper for writing numeric vectors. | ||
template <typename Impl> | ||
template <typename Number> | ||
size_t BlobSerializer<Impl>::WriteArithmeticVector( | ||
const std::vector<Number>& data) { | ||
static_assert(std::is_arithmetic_v<Number>, "Arithmetic type"); | ||
return WriteArithmetic(data.data(), data.size()); | ||
} | ||
|
||
// Helper for writing non-numeric vectors. | ||
template <typename Impl> | ||
template <typename T> | ||
size_t BlobSerializer<Impl>::WriteNonArithmeticVector( | ||
const std::vector<T>& data) { | ||
static_assert(!std::is_arithmetic_v<T>, "Arithmetic type"); | ||
DCHECK_GT(data.size(), | ||
0); // Should not write contents for vectors of size 0. | ||
size_t written_total = 0; | ||
bool original_is_debug = is_debug; | ||
is_debug = original_is_debug && !std::is_same_v<T, std::string>; | ||
for (size_t i = 0; i < data.size(); ++i) { | ||
if (is_debug) { | ||
Debug("\n[%d] ", i); | ||
} | ||
written_total += WriteElement<T>(data[i]); | ||
} | ||
is_debug = original_is_debug; | ||
|
||
return written_total; | ||
} | ||
|
||
template <typename Impl> | ||
template <typename T> | ||
size_t BlobSerializer<Impl>::WriteElement(const T& data) { | ||
if constexpr (std::is_arithmetic_v<T>) { | ||
return WriteArithmetic<T>(data); | ||
} else if constexpr (std::is_same_v<T, std::string>) { | ||
return WriteString(data); | ||
} else { | ||
return impl()->template Write<T>(data); | ||
} | ||
} | ||
|
||
} // namespace node | ||
|
||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | ||
|
||
#endif // SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.