-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Align the ShimMap iterator behavior with native Maps #27292
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
Conversation
a094875
to
edb4be4
Compare
@rbuckton @sheetalkamat @weswigham can you take a look? |
A unit test in the |
Hi @weswigham
Thank you, I will create a unit test for the shimMap. I think I will even create one that also tests iteration when values are deleted (which will currently fail), because I think I can rework the iterator implementation to match exactly the behavior of a native Map, including visiting entries in insertion order and handling the case when values are deleted while iteration is still running ( In the current state, this PR handles the case when values are added during iteration, but when values are deleted during iteration, the iterator will throw when continuing it. In my first comment, I noted this could be handled by using a linked list. I think this can even work without creating a memory leak (as I wrote in the comment) and with better performance. My idea is as follows: Let's say that we create a map and add some values to it ( let map = createMap<string>();
map.set("A", 1);
map.set("B", 2);
map.set("C", 3);
map.set("D", 4); Then, we create two iterators, and we advanced one of the iterators by two elements: let iterator1 = map.entries();
let iterator2 = map.entries();
iterator1.next(); // -> A
iterator1.next(); // -> B Now, the objects will look like this: Now, delete map.delete("B"); This will change the forward reference of Now, delete map.delete("C"); This will change the forward reference of Because Now, add map.set("E", 5);
map.delete("A"); This means while elements This solves the initial problem I had in the first commit, where the Map had to contain a reference to all active iterators (in order to adjust their indexes when an entry was deleted), so if a iterator was thrown away before iteration finished, the map still had a reference to it. This is no longer the case when using the linked list. This should ensure that the iteration of the |
Done: The
A minor performance drawback is that when calling |
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.
Looks pretty good to me now (test verification is a bit obtuse for my tastes, but it's OK) - @rbuckton ?
I have checked that this also fixes #29193.
Sorry, I didn't have a better idea how to test the iterator behavior 😇 |
Sorry, I think there is still a minor bug in the |
OK, fixed: The backward reference of the next entry was not correctly adjusted in |
…t values that are added while forEach is running. Fixes microsoft#26090
…ing iterators to continue once an entry has been deleted from the map. Fixes microsoft#26090
This will test that iteration is in insertion order, new entries added during iteration will be visited by the iterator, and values can be deleted while an iterator is running.
…ave the same as with native Maps. This includes: - Entries are visited in insertion order - New entries added during iteration will be visited - Entries that are removed during iteration (before being visited) will not be visited Fixes microsoft#26090
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.
Just one minor issue to address, if you could.
Thanks for the contribution! |
Hi,
this PR adjusts the
shimMap
that is used bycreateMap<T>()
for IE 11/ES 5 environments (instead of a nativeMap
) to visit values that are added while an iteration orforEach()
is running (which is documented for a nativeMap
). Previously, new values during iteration would not be visited, causing problems in IE 11 as described in #26090.I used the same mechanism for both the
forEach
call and iterators created with.entries()
.Note: With this PR, theshimMap
does not support deleting values while an iteration is still running - in this case, when the iterator/forEach loop continues after the delete operation, it will throw an error.I think it is possible to also support deleting values while an iteration is active using a linked list, but with the caveat that a memory leak could occur if you keep a reference to an non-finished iterator, and then continuously add and delete values from the map. Additionally, as long as there are unfinished iterators (that may or may not be reachable), delete operations on the map would be slow, as they would need to search the iterator key elements.Update: I have reworked the implementation so that the
shimMap
should now have the same behavior as a native map for iterators andforEach()
loops (see comment below). This means that entries are iterated in insertion order, values added during iteration will be visited, and values removed during iteration (before they were visited) will not be visited.shimMap
.Fixes #26090
Fixes #29193