-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
console,util: avoid pair array generation in C++ #20831
Conversation
Use a plain `[key, value, key, value]`-style list instead of an array of pairs for inspecting collections. This also fixes a bug with `console.table()` where inspecting a non-key-value `MapIterator` would have led to odd results. Refs: nodejs#20719 (comment)
a6150b1
to
c90c676
Compare
for (let i = 0; i < ret.length; ++i) | ||
ret[i] = [list[2 * i], list[2 * i + 1]]; | ||
return ret; | ||
} |
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.
We could use the same pattern as in weak maps instead of first zipping this. This step is just overhead (even though the result is nicer to read).
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.
Yes, but it gets pretty tricky to do that, at least for me… we are passing the individual pair arrays to formatValue
, and it’s not obvious how/whether to short-circuit around that
(Extreme edge case: Calling formatValue()
on the individual keys/values rather than the pairs even makes a difference in depth
…)
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 am not sure in what way this should have any influence on the depth
?
ret->Set(env->context(), 0, entries).FromJust(); | ||
ret->Set(env->context(), 1, v8::Boolean::New(env->isolate(), is_key_value)) | ||
.FromJust(); | ||
return args.GetReturnValue().Set(ret); |
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.
We do not need the information about the key value pairs as we already have that when calling this function. The JS side has to be adjusted to the way it worked before to accomplish that.
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.
We do not need the information about the key value pairs as we already have that when calling this function.
Not for Map iterators, and I’m not aware of how we could know that in advance.
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.
The way this was done before in JS allowed this. We just pretty much have to revert the JS changes from the former PR.
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.
@BridgeAR Not really? When we had the V8 builtins available, we could only tell them apart because some Map iterators gave us pairs and others didn’t, but if we want to avoid pair creation, then we need this.
Concrete example: This is necessary to distinguish new Map([[1,2],[3,4]]).entries()
from new Map([['a',1],['b',2],['c',3],['d',4]]).values()
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.
Thanks! I did not think about new Map().entries()
anymore. However, this is only necessary in case of map iterators. So we could tell C++ if we want the return value to be wrapped in a extra array for the map iterators and just directly return the array for all set iterators.
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.
Hm, I just checked https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries and now I remember why the return value for entries with a set iterator was actually so weird. That was indeed by design. I am a bit on the edge to follow that or not... As far as I know, we can not detect that anymore, right?
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.
As far as I know, we can not detect that anymore, right?
Yes. If it helps, our behaviour is aligned with Chromium’s now (for that reason), and I think that either can be seen as valid.
|
||
const setlike = setIter || isSet(tabularData); | ||
const setlike = setIter || (mapIter && !isKeyValue) || isSet(tabularData); |
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 am not a fan of this solution. What we should do is to detect the actual type of the tabularData
before ever overriding that variable. I would just use a second variable to make this easier. As in:
let data = tabularData;
if (mapIter) {
...
}
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’m not sure I understand this comment… Second argument to which function exactly?
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.
Sorry, second variable (not argument).
The reason for the issue is that the type can not be properly detected anymore after overriding the original input. So we need a reference to the original input that we never override and one that could potentially be changed. That way the implementation should be easier. I guess I should not have accepted the PR to be landed originally :/
If you want, I can take a stab at this.
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 mean, we did override tabularData
before too, so this isn’t really a step back on that (if that’s the variable you’re referring to).
Tbh, I’m still not really getting what you’re trying to say, but it might just be easier to talk about concrete code, yes. :)
That way the implementation should be easier. I guess I should not have accepted the PR to be landed originally :/
Are you talking about #20719 or the one that introduced the table code in the first place? The former one did not make any changes to this code that go beyond trivial…
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 mean the original table code in the first place.
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 am to tired tonight but I am going to have a look at it tomorrow. Is it fine to just push to your branch directly?
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.
Yeah, feel free to do that. :)
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.
Great :)
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.
After looking into this closer it does indeed require some deeper changes for what I thought about.
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.
LGTM in general. Some minor comments.
if (mapIter) | ||
tabularData = previewEntries(tabularData); | ||
[ tabularData, isKeyValue ] = previewEntries(tabularData); |
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.
The syntax makes me go 😬
Let's make it
if (mapIter) {
;([tabularData, isKeyValue] = previewEntries(tabularData));
}
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.
that leading semi isn't really node style, but i agree to brackets + wrapping in parens
@@ -367,9 +376,9 @@ Console.prototype.table = function(tabularData, properties) { | |||
|
|||
const setIter = isSetIterator(tabularData); | |||
if (setIter) | |||
tabularData = previewEntries(tabularData); | |||
[ tabularData ] = previewEntries(tabularData); |
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 we make it previewEntries(tabularData)[0]
instead?
const entries = previewEntries(value).slice(0, maxArrayLength + 1); | ||
const remainder = entries.length > maxArrayLength; | ||
const len = entries.length - (remainder ? 1 : 0); | ||
const [ entries ] = previewEntries(value).slice(0, (maxArrayLength + 1) * 2); |
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.
nit: we don't usually put spaces inside of []
. [entries]
is fine.
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.
The slice is actually unnecessary overhead. The limitation is done below and this has no effect (there are just two entries returned).
@@ -447,13 +447,13 @@ assert.strictEqual(util.inspect(-5e-324), '-5e-324'); | |||
{ | |||
const map = new Map(); | |||
map.set(1, 2); | |||
const vals = previewEntries(map.entries()); | |||
const [ vals ] = previewEntries(map.entries()); |
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.
Might be a good idea for us to test isKeyValue
as well.
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 couldn't find anything to nitpick so with the other comments handled this lgtm
@BridgeAR I wanted to wait for you to push changes you’d like to see before I continue with this PR … where are you at regarding that? Otherwise I’d probably address some of the newer comments here first |
@addaleax I have my local change ready but it became somewhat more involved, so I decided to just open a PR on top of this one. I am going to rebase when this PR lands. |
@addaleax did you have a look at my follow up PR? :-) |
Use a plain `[key, value, key, value]`-style list instead of an array of pairs for inspecting collections. This also fixes a bug with `console.table()` where inspecting a non-key-value `MapIterator` would have led to odd results. PR-URL: nodejs#20831 Refs: nodejs#20719 (comment) Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
Landed in db49589. I fixed the eslint errors while landing. |
Use a plain `[key, value, key, value]`-style list instead of an array of pairs for inspecting collections. This also fixes a bug with `console.table()` where inspecting a non-key-value `MapIterator` would have led to odd results. PR-URL: #20831 Refs: #20719 (comment) Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
Use a plain
[key, value, key, value]
-style list insteadof an array of pairs for inspecting collections.
This also fixes a bug with
console.table()
whereinspecting a non-key-value
MapIterator
would haveled to odd results.
Refs: #20719 (comment)
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes