-
Notifications
You must be signed in to change notification settings - Fork 40
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
Thoughts on breaking usage convention for Data.withUnsafeBytes
?
#73
Comments
Honest answer: I got this from StackOverflow Now a more constructive answer. Now I browsed through private let originalBuffer : UnsafeMutableBufferPointer<UInt8>!
public init(data : Data, cache : FBReaderCache? = FBReaderCache()) {
self.count = data.count
self.cache = cache
let pointer : UnsafeMutablePointer<UInt8> = UnsafeMutablePointer.allocate(capacity: data.count)
self.originalBuffer = UnsafeMutableBufferPointer(start: pointer, count: data.count)
_ = data.copyBytes(to: originalBuffer)
self.buffer = UnsafeRawPointer(pointer)
}
public func freeMemory(){
if let originalBuffer = originalBuffer,
let pointer = originalBuffer.baseAddress {
pointer.deinitialize(count: count)
}
} This implementation is safer and seems to solve the data ownership problem. In previous versions user had to keep a reference to data around if they wanted to use I will think about it a bit more, but I guess it would be a good enhancement, and I will have to change the code generator a bit. Also I am not 100% sure about |
I have by no means used the Swift pointer API extensively, and I don't know this codebase, so with the risk of sounding like I don't know what I'm doing 🙂:
That would shorten the above to
From glancing over the code I can only find one use of the fact that The
From what I've gathered by asking on StackOverflow, the
In general, if you'd add some comments to types and important functions it'd be interesting to look at. |
And to answer myself 2: Disregard. Seems that Github just didn't want to show me correct results when searching for "fromByteArray". Should have relied on Chrome search instead of Github's UI team ><. Also realized there is some black box code generation in this project. Read up on flatbuffers and it seems they somehow accounts for memory alignment? Beats me how, I was led to believe they weren't invariant between architectures. But that's convenient! |
FWIW, I don't think it would be unreasonable to take a local copy (and free it accordingly) of the Data as this is a usability convenience initialiser - anyone caring about zero-copy and high performance would opt for the UnsafeRawPointer initialiser (even someone holding a Data object outside could always use that as well by using a data.withUnsafeBytes closure that encapsulates the whole usage of the FBMemoryReader if needed). The current code is basically unsafe though, good catch. Also, that being said, "withUnsafeBytes" wouldn't need to copy necessarily if Data knows that the bytes are contiguous in memory, so I would not assume that is being done just based on SO. Wrt to freeMemory(), shouldn't that simple be done in deinit{} ? "Can't we skip originalBuffer completely in your suggestion?" "The fromByteArray looks to me like it could suffer from alignment problems" |
@anohren Will respond point by point 🙂
Also @anohren if you are interested in how the builder and reader are used I have a couple of integration tests which work with generated classes: The first one is a complex example which use most of FlatBuffers features but is a hierarchically structured The second one is an example of a complex cyclical graph. Documenting the API and also udtaing the Wiki is also on my list 😊 |
Interesting stuff, thanks for replying. Good and bad news is that the implementation of
So it might not break...yet.
I can recommend that document for further reading though. It covers most topics. At first I thought strings constructed with
|
Another alternative would be to change the reader implementation to always use data.withUnsafeBytes instead of directly accessing the stored pointer, then it would be safe and no copy would be needed, but it could have performance implications if not done carefully and would probably need some measuring... |
Nope, I was unclear. I agree with you, and proposed to rename this init parameter to |
It seems to me that this initializer is not following the documentation of
withUnsafeBytes
which says not to use the pointer outside the passed closure. What's the reason for writing the init like this? Of course, in absence of a comment, I don't know of its specific use case.AFAIK
Data
doesn't guarantee using contiguous memory. What are the implications of that here?Do you happen to know why the pointer shouldn't be accessed outside the closure?
The text was updated successfully, but these errors were encountered: