-
Notifications
You must be signed in to change notification settings - Fork 30.6k
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
src: unify implementations of Utf8Value, TwoByteValue, etc. #6357
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,77 +178,102 @@ inline TypeName* Unwrap(v8::Local<v8::Object> object); | |
|
||
inline void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen); | ||
|
||
class Utf8Value { | ||
// Allocates an array of member type T. For up to kStackStorageSize items, | ||
// the stack is used, otherwise malloc(). | ||
template <typename T, size_t kStackStorageSize = 1024> | ||
class MaybeStackBuffer { | ||
public: | ||
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
const T* out() const { | ||
return buf_; | ||
} | ||
|
||
~Utf8Value() { | ||
if (str_ != str_st_) | ||
free(str_); | ||
T* out() { | ||
return buf_; | ||
} | ||
|
||
char* operator*() { | ||
return str_; | ||
}; | ||
// operator* for compatibility with `v8::String::(Utf8)Value` | ||
T* operator*() { | ||
return buf_; | ||
} | ||
|
||
const char* operator*() const { | ||
return str_; | ||
}; | ||
const T* operator*() const { | ||
return buf_; | ||
} | ||
|
||
size_t length() const { | ||
return length_; | ||
}; | ||
|
||
private: | ||
size_t length_; | ||
char* str_; | ||
char str_st_[1024]; | ||
}; | ||
} | ||
|
||
class TwoByteValue { | ||
public: | ||
explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
// Call to make sure enough space for `storage` entries is available. | ||
// There can only be 1 call to AllocateSufficientStorage or Invalidate | ||
// per instance. | ||
void AllocateSufficientStorage(size_t storage) { | ||
if (storage <= kStackStorageSize) { | ||
buf_ = buf_st_; | ||
} else { | ||
// Guard against overflow. | ||
CHECK_LE(storage, sizeof(T) * storage); | ||
|
||
buf_ = static_cast<T*>(malloc(sizeof(T) * storage)); | ||
CHECK_NE(buf_, nullptr); | ||
} | ||
|
||
// Remember how much was allocated to check against that in SetLength(). | ||
length_ = storage; | ||
} | ||
|
||
~TwoByteValue() { | ||
if (str_ != str_st_) | ||
free(str_); | ||
void SetLength(size_t length) { | ||
// length_ stores how much memory was allocated. | ||
CHECK_LE(length, length_); | ||
length_ = length; | ||
} | ||
|
||
uint16_t* operator*() { | ||
return str_; | ||
}; | ||
void SetLengthAndZeroTerminate(size_t length) { | ||
// length_ stores how much memory was allocated. | ||
CHECK_LE(length + 1, length_); | ||
SetLength(length); | ||
|
||
const uint16_t* operator*() const { | ||
return str_; | ||
}; | ||
// T() is 0 for integer types, nullptr for pointers, etc. | ||
buf_[length] = T(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this write past the end of the buffer in most cases? The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They call |
||
} | ||
|
||
size_t length() const { | ||
return length_; | ||
}; | ||
// Make derefencing this object return nullptr. | ||
// Calling this is mutually exclusive with calling | ||
// AllocateSufficientStorage. | ||
void Invalidate() { | ||
CHECK_EQ(buf_, buf_st_); | ||
length_ = 0; | ||
buf_ = nullptr; | ||
} | ||
|
||
MaybeStackBuffer() : length_(0), buf_(buf_st_) { | ||
// Default to a zero-length, null-terminated buffer. | ||
buf_[0] = T(); | ||
} | ||
|
||
~MaybeStackBuffer() { | ||
if (buf_ != buf_st_) | ||
free(buf_); | ||
} | ||
private: | ||
size_t length_; | ||
uint16_t* str_; | ||
uint16_t str_st_[1024]; | ||
T* buf_; | ||
T buf_st_[kStackStorageSize]; | ||
}; | ||
|
||
class BufferValue { | ||
class Utf8Value : public MaybeStackBuffer<char> { | ||
public: | ||
explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
|
||
~BufferValue() { | ||
if (str_ != str_st_) | ||
free(str_); | ||
} | ||
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
}; | ||
|
||
const char* operator*() const { | ||
return fail_ ? nullptr : str_; | ||
}; | ||
class TwoByteValue : public MaybeStackBuffer<uint16_t> { | ||
public: | ||
explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
}; | ||
|
||
private: | ||
char* str_; | ||
char str_st_[1024]; | ||
bool fail_; | ||
class BufferValue : public MaybeStackBuffer<char> { | ||
public: | ||
explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
}; | ||
|
||
} // namespace node | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I suggest you call this method e.g.
buffer()
and stay away from operator overloading?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bnoordhuis 1000 % yes, but this is basically just the
operator*
from the original classes, as it is used in ~100 places in the rest of the source code. If you’re okay with that, I’m happy to rename it (but maybe would prefer.data()
as the name?).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I guess that would make it a much more intrusive change. I mentioned it because whenever I see code with
**this
in it, I get itchy..buffer()
hints more at mutability, IMO, but maybe that's just me.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just “standardizing” the
out()
method that StringBytes::InlineDecoder already has, and using that for the internal stuff too (instead of**this
)?I have nothing against
.buffer()
, and on second thought that sounds like a good name, but I’d like to keep this changeset small and pointing in the direction of a more consistent API.