-
Notifications
You must be signed in to change notification settings - Fork 29.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
buffer: add {read|write}[U]Int64{BE|LE} methods #15152
Conversation
I'm leaning more towards -1 because of the current lack of support in the language (and thus an inconsistency with the return values for the 64-bit However, it is probably best to just wait until something like the BigInt ES proposal gets accepted before adding 64-bit integer support. |
(edited because the message above was edited)
Do we do that anywhere where the integer could be greater than
They can use Would you be less opposed to returning a number when it's less than
That's far in the future. Besides, with BigInt reading 64-bit integers would still be inconsistent. |
So there would be an inconsistency in how we deal with 64-bit integer values in core. I don't think that would be a good thing.
Maybe, maybe not. It's already at stage 3. Besides, we've gone this long without 64-bit integer Buffer |
Can you give specific examples?
I'm not convinced that using BigInt would be the most appropriate way. A common usecase for 64-bit integers is some kind of an identifier, in which case a primitive is more convenient (and actually more consistent with other read/write functions). |
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.
I don’t see anything terribly wrong with this, fwiw.
@@ -1722,6 +1722,22 @@ console.log(buf.readInt32LE()); | |||
console.log(buf.readInt32LE(1)); | |||
``` | |||
|
|||
### buf.readInt64LE(offset[, noAssert]) | |||
### buf.readInt64BE(offset[, noAssert]) |
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.
<!-- YAML
added: replaceme
-->
:)
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]); | ||
SPREAD_BUFFER_ARG(args[0], ts_obj); | ||
|
||
uint32_t offset = args[1]->Uint32Value(); |
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 you use the overload that takes a context
argument?
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.
doc/api/buffer.md
Outdated
|
||
* `offset` {integer} Where to start reading. Must satisfy: `0 <= offset <= buf.length - 8` | ||
* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` | ||
* Returns: {integer} |
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.
is this accurate?
src/node_buffer.cc
Outdated
|
||
T val; | ||
if (args[1]->IsNumber()) { | ||
val = args[1]->IntegerValue(); |
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.
ditto (using the non-deprecated overload taking a context
argument)
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.
@addaleax I didn't realize that this overload is deprecated. Is this documented somewhere?
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.
@seishun Yes:
Lines 2297 to 2309 in 94be2b1
V8_WARN_UNUSED_RESULT Maybe<bool> BooleanValue(Local<Context> context) const; | |
V8_WARN_UNUSED_RESULT Maybe<double> NumberValue(Local<Context> context) const; | |
V8_WARN_UNUSED_RESULT Maybe<int64_t> IntegerValue( | |
Local<Context> context) const; | |
V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value( | |
Local<Context> context) const; | |
V8_WARN_UNUSED_RESULT Maybe<int32_t> Int32Value(Local<Context> context) const; | |
V8_DEPRECATE_SOON("Use maybe version", bool BooleanValue() const); | |
V8_DEPRECATE_SOON("Use maybe version", double NumberValue() const); | |
V8_DEPRECATE_SOON("Use maybe version", int64_t IntegerValue() const); | |
V8_DEPRECATE_SOON("Use maybe version", uint32_t Uint32Value() const); | |
V8_DEPRECATE_SOON("Use maybe version", int32_t Int32Value() const); |
And also V8 API changes:
Ongoing and Planned Changes
... APIs that are marked as
V8_DEPRECATE_SOON
will be marked asV8_DEPRECATED
in the future. APIs marked asV8_DEPRECATED
will usually be removed after one V8 release.
- Introduction of MaybeLocal<> and Maybe<> APIs: bug
- ...
I don't see the necessity of waiting until BigInt. In fact when it's introduced we can add a readBig[U]Int64 to match DataView. IMO returning a string isn't ideal, but the fact that the developer can cast it easily to a number by prefixing a |
Just alternatively, the return could be an array similar to that used by |
@jasnell an array is difficult to convert to either a number or a string, and it would be inconsistent with other |
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.
I wonder which possible use cases this might benefit. Sure, people can read 64 bit values as strings, and can then parse (some of them!) as numbers, but there is not even a guarantee that arithmetic operations with those numbers will be accurate, and there is still no fixed-size arithmetic.
If you decide to return numbers as a decimal representation, that should probably be mentioned in the docs.
doc/api/buffer.md
Outdated
format (`writeUInt64BE()` writes big endian, `writeUInt64LE()` writes little | ||
endian). `value` should be a valid unsigned 64-bit integer or a String | ||
representation of one. Behavior is undefined when `value` is anything other than | ||
an unsigned 32-bit integer or a String representation of one. |
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.
32 → 64
doc/api/buffer.md
Outdated
format (`writeInt64BE()` writes big endian, `writeInt64LE()` writes little | ||
endian). `value` *should* be a valid signed 64-bit integer or a String | ||
representation of one. Behavior is undefined when `value` is anything other than | ||
a signed 32-bit integer or a String representation of one. |
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.
32 → 64
Not everyone requires arithmetic operations on the values they read or write. As I've mentioned before, 64-bit integers are often used as identifiers, for example SteamID. |
cc @nodejs/collaborators need more input. |
@littledan how far is BigInt from V8? Edit: found https://bugs.chromium.org/p/v8/issues/detail?id=6791 |
IMHO we should wait for BigInt. |
Sorry, missed that I was asked to review this. I'm also in the "Waiting for Godot^WBigInt" camp; it's at stage 3, implementation work has started, it won't be long (no C programmer pun intended.) |
I'm working on BigInt specifically in order to enable these use cases. Strings seem like a functioning workaround, but I'm wondering what's motivating adding this to core right now at a time when BigInts are actually under development. |
Well, there are several reasons Node.js might do this:
That said, I vote "wait for BigInt" too. |
Whether BigInt is coming or not, I am not convinced that we should represent decimals as strings just to make them accessible at all (even though I won't block this PR). I think very few users need to represent 64 bit numbers as decimal strings and even fewer need to use a buffer to convert to and from those numbers. With BigInt coming up, we got a promising alternative, which only reinforces my opinion. |
I believe we should be conservative with breaking (in this case, future) API, and we should always aim for consistency and elegance when it comes to naming things. Given that, I'm also voting we wait for BigInt. |
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.
Making it explicit
@seishun I am sure this was quite some work but I think this will not land and I would rather close it for now. Are you ok with that? I think it is a good basis for a PR as soon as v8 supports BigInt out of the box! |
Yes, I'm okay with that. |
@littledan @mscdex @bnoordhuis Any way I can be informed when a V8 version with BigInt support makes it to Node.js? |
@seishun Not really (other than reading V8/node changelogs), but for right now you can track the BigInt repo or the ECMAScript finished proposals list to watch for when the BigInt proposal reaches stage 4 (finished). I doubt V8 would add support for BigInt (behind a flag or otherwise) before it reaches stage 4, but I could be wrong about that as I don't know of their plans. |
@seishun You can also track this issue: https://bugs.chromium.org/p/v8/issues/detail?id=6791 |
It does look like they do have it behind a flag ( |
This is basically a resurrection of @TooTallNate's PR #1750 with a couple differences:
read[U]Int64{BE|LE}
always returns strings to make the output more predictable.address()
method, and thus no changes to the inspect output for BuffersI'm not sure how to deal with attribution. @TooTallNate did most of the work here, but I also did significant work rebasing and updating.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
buffer