-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
Adds UnsafeCollectionOperations for unsafe access to RepeatedField<T> #16772
base: main
Are you sure you want to change the base?
Adds UnsafeCollectionOperations for unsafe access to RepeatedField<T> #16772
Conversation
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
@JamesNK We're aware that if the repeated field is modified while the span is "active", it may or may not reflect the changes (e.g. add/remove operations will not be seen in terms of the length, and if the array is reallocated any further updates won't be visible at all) - but do you think that's reasonable behavior, so long as we document that appropriately? (I'd just say that the state of the span is undefined after any modifications.) Any other thoughts about this PR? |
Modification is the problem. Sometimes the span reflects changes, sometimes it doesn't. I like the idea, but I don't think it should be a property on A property is easily discoverable with autocomplete. On the other hand, a method on a type is something people have to go looking to use, and they'll hopefully read the docs about why they should (or shouldn't) use the method. foreach (var product in CollectionsMarshal.AsSpan(response.Products))
{
// do stuff
} I took a look at var request = new Request();
CollectionsMarshal.SetCount(request.Products, count: 1000);
var productsSpan = CollectionsMarshal.AsSpan(request.Products);
for (var i = 0; i < productsSpan.Length; i++)
{
productsSpan[i] = // do stuff
} This would save many internal array allocations and copies as the repeated field grows. However, SetCount (a new version for repeated fields) + modifying the span directly wouldn't guarantee the values in the repeated field aren't null. |
I changed the implementation to include your suggestions. There is already a similar class |
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 haven't reviewed the tests in detail as I'm suggesting quite significant implementation changes.
csharp/src/Google.Protobuf.Test/Collections/UnsafeCollectionOperationsTest.cs
Show resolved
Hide resolved
csharp/src/Google.Protobuf.Test/Collections/UnsafeCollectionOperationsTest.cs
Outdated
Show resolved
Hide resolved
csharp/src/Google.Protobuf.Test/Collections/UnsafeCollectionOperationsTest.cs
Outdated
Show resolved
Hide resolved
@jskeet I also believe a few things were performance optimizations in the I incorporated your feedback into this pull request to better align with the behavior of Protobuf. I left a couple of comments open to provide some context. Feel free to close them as needed after review, as everything should be resolved. |
@jskeet One last remark. The tests are ported from |
I'll have a look tomorrow. I would say that I'm not as interested in alignment with CollectionsMarshal as with consistency with the rest of this codebase, and clarity of code and usage. |
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 think its good! Some minor comment and test improvements in feedback
@@ -1,7 +1,7 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
|
|||
<PropertyGroup> | |||
<TargetFrameworks>net462;net6.0</TargetFrameworks> |
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.
How come net462 is removed? I think it's important to run tests on .NET Framework. If some features aren't supported on .NET Framework then they can be selectively #ifdef
ed out.
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.
Oops. I removed it to be able to run the test on my unix machine
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.
Down to just nits now - it feels like we're very close, thanks very much for this!
cc @amanda-tarafa for any additional thoughts |
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.
A couple of comments, but looks good otherwise.
@JamesNK @jskeet @amanda-tarafa |
Thanks - I'm afraid at this point I won't get to this until Monday, but hopefully I'll be able to look then. |
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 down to comment nits from my side.
@jskeet Comments are resolved 🚀 |
@JamesNK: Could you take one final pass at this? It looks good to me, but due to the unsafe aspects of it, I'd appreciate a double-check. After that, I can get it reviewed by a member of the protobuf team and merged. |
@mkruskal-google: We've reviewed this from a .NET perspective. Let me know if you'd like any more background. (But basically this allows very efficient access to a repeated field, with caveats around anything that might resize it.) |
This is a proposal to add
UnsafeCollectionOperations
for fast access onRepeatedField<T>
#16745