-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Add CollectionsMarshal.GetValueRefOrAddDefault #54611
Add CollectionsMarshal.GetValueRefOrAddDefault #54611
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @eiriktsarpalis Issue DetailsContributes to #27062namespace System.Runtime.InteropServices
{
public static ref TValue? GetValueRefOrAddDefault<TKey, TValue>(Dictionary<TKey, TValue> dictionary, TKey key, out bool exists)
where TKey : notnull;
}
}
|
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
Outdated
Show resolved
Hide resolved
@jkotas Could you clarify what the overhead of this new method would be, and whether it would be a blocker for this PR? This would be a very neat feature to have, and the API itself has been approved by API review too - if it's just the current implementation that's an issue would any of the proposed approaches help? As in, moving the code to a diferent spot, etc. Thanks! 🙂 |
It makes every Dictionary instantiation more expensive, in particular with AOT. |
I see. If the issue is specifically with the overhead of dictionary instantiations, would moving the code to a separate type (eg. a nested type within dictionary) solve that? That would only ever be loaded when the method is actually used, right? 🤔 |
Yes, it would solve that. |
8b9e772
to
31d7120
Compare
31d7120
to
99523ba
Compare
Test failures should be unrelated, and the changes in 99523ba addresses Jan's concerns on additional overhead being added to |
99523ba
to
5367083
Compare
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.
@Sergio0694 Thanks for this! Can you also add a unit test for the randomized hash logic? I think the appropriate place to add this would be in the file https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs.
There's no need to modify RunDictionaryTest
(line 93 of that file) to run a CollectionsMarshal
test for every possible combination; that's probably overkill. Instead, what you can do is immediately before line 93, insert a manual call that looks something like:
RunCollectionTestCommon(
() => new Dictionary<string, object>(StringComparison.Ordinal),
(dictionary, key) => CollectionsMarshal.GetRef(dictionary, key, out _) = null,
(dictionary, key) => dictionary.ContainsKey(key),
dictionary => dictionary.Comparer,
expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType,
expectedPublicComparerBeforeCollisionThreshold: StringComparer.Ordinal,
expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType);
In a nutshell, this utilizes the existing test infrastructure to generate a whole bunch of collisions, but the delegate you provide will force it to use your new CollectionsMarshal
method instead of Add
. This will get regression test coverage for string collision scenarios in this method.
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CollectionsMarshal.cs
Outdated
Show resolved
Hide resolved
This avoids the additional overhead when loading Dictionary<TKey, TValue> instances, especially in AOT scenarios, and it makes the new API pay for play.
5367083
to
1d7e386
Compare
...stem.Runtime.InteropServices/tests/System/Runtime/InteropServices/CollectionsMarshalTests.cs
Outdated
Show resolved
Hide resolved
...stem.Runtime.InteropServices/tests/System/Runtime/InteropServices/CollectionsMarshalTests.cs
Show resolved
Hide resolved
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.
Other than minor feedback, LGTM. Thanks!
A reminder for the future - try to avoid rebase & force-push after reviews have started. Makes it a little more complicated for us since we can't rely on the GitHub web UI and instead we need to generate incremental diffs manually. |
Oh, I'm sorry, I didn't realize that. Will definitely avoid doing that again in the future! 😅 |
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 so much! :D
Contributes to #27062