Skip to content
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 readonly dictionary wrapper that removes enumerator alloc #6163

Merged
merged 3 commits into from Feb 2, 2024

Conversation

smoogipoo
Copy link
Contributor

@smoogipoo smoogipoo commented Feb 1, 2024

I find it pretty silly that this is still a thing even going into .NET 8. Hoping to use this for ppy/osu#26863.

Method Mean Error StdDev Gen0 Allocated
Dictionary 35.05 us 0.692 us 1.035 us - -
DictionaryAsReadOnly 91.75 us 1.833 us 4.212 us 22.9492 48000 B
DictionaryAsSlimReadOnly 34.67 us 0.690 us 1.345 us - -
Keys 28.73 us 0.079 us 0.074 us - -
KeysAsReadOnly 81.24 us 0.101 us 0.095 us 19.0430 40000 B
KeysAsSlimReadOnly 28.75 us 0.056 us 0.052 us - -
Values 28.50 us 0.083 us 0.074 us - -
ValuesAsReadOnly 81.41 us 1.241 us 0.969 us 19.0430 40000 B
ValuesAsSlimReadOnly 28.58 us 0.074 us 0.058 us - -

In contrast to SlimReadOnlyListWrapper<T>, the only thing gained by implementing any of the other interfaces is CopyTo(), so I've taken the liberty of not implementing every dictionary interface in existence here.

/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
/// <returns>The read-only view.</returns>
public static SlimReadOnlyDictionaryWrapper<TKey, TValue> AsSlimReadOnly<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the namespace of this is a little unfortunate but probably not worth incurring a source breaking change for

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could split it out into a DictionaryExtensions, but it felt like too much. If you'd feel better with that then let me know and I'll do it.

Comment on lines +20 to +21
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
=> dict.GetEnumerator();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and the non-generic IEnumerator one) still boxes, but I guess SlimReadOnlyListWrapper does the same so maybe fine.

Copy link
Contributor Author

@smoogipoo smoogipoo Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, and is the way you're supposed to implement this. The only relevant case is foreach ((SlimReadOnlyDictionary<>)dict), if you go via the interface then you're SOL no matter what.

@bdach bdach enabled auto-merge February 2, 2024 10:18
@bdach bdach merged commit 77a0ccd into ppy:master Feb 2, 2024
13 checks passed
smoogipoo pushed a commit to smoogipoo/osu-framework that referenced this pull request Feb 3, 2024
Add readonly dictionary wrapper that removes enumerator alloc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants