swift-nio
swift-nio copied to clipboard
ByteBufferView: implement most Collection/Sequence customisation points
ByteBufferView
is a Collection
of UInt8
which "views" into a ByteBuffer
. Right now, we basically only implement the subscript
which vends individual bytes. That's good enough to implement Collection
/Sequence
(and a bunch of more specialised sub-protocols) but it's not very fast at all.
Especially methods like firstIndex(of:)
or firstIndex(where:)
will be very slow because it'll repeatedly call the subscript for every byte. It would be much faster to just forward the Collection
/Sequence
customisation points directly to the underlying bytes.
Generally, this will look something like
public func _customTHEFUNCTION(ARGUMENTS) {
return try self._buffer.withVeryUnsafeBytes { ptr in
let ptr = UnsafeRawBufferPointer(start: ptr.baseAddress!.advanced(by: self._range.lowerBound), count: self._range.count))
return ptr.THEFUNCTION(ARGUMENTS)
}
}
so essentially we just forward all operations into the UnsafeRawBufferPointer
to the bytes this ByteBufferView
contains.
The Collection
customisation points we should implement are
- [x]
_customIndexOfEquatableElement
usingptr.firstIndex(of:)
[done in #1394] - [x]
_customLastIndexOfEquatableElement
usingptr.lastIndex(of:)
[done in #1394] - [ ] all three variants of
_failEarlyRangeCheck
by just checking theself._range
- [x]
_customContainsEquatableElement
usingptr.contains()
- [x]
_copyToContiguousArray
- [x]
_copyContents
We also don't need to implement all of those in one go, this can be done in multiple PRs.
Some notes:
- we should back the gains up by benchmarks
- this requires basically no SwiftNIO knowledge but intermediate Swift knowledge about how protocols/Collection/Sequence
I'm trying to resolve this task but it makes confused when you said
all three variants of _failEarlyRangeCheck by just checking the self._range
I thought that we should check bounds
parameter instead of self._range
. Did I misunderstand anything?
@trungducc thank you, that's awesome. I think this is just a misunderstanding. I think we need to compare that the bounds
parameter of _failEarlyRangeCheck
lies within self._range
's bounds (self._range.lowerBound
& self._range.upperBound) in
ByteBufferView`.
@weissi Oh yes. That makes sense. I didn't think about it. Thank you for pointing out!
Added _copyContents
in #2039. I don't think we need to do _copyToContiguousArray
as the default implementation leans on _copyContents
, so improving the latter improves the former, so I'm checking that off too.
_customContainsEquatableElement
was done in https://github.com/apple/swift-nio/pull/2044
@trungducc thank you, that's awesome. I think this is just a misunderstanding. I think we need to compare that the
bounds
parameter of_failEarlyRangeCheck
lies withinself._range
's bounds (self._range.lowerBound
&self._range.upperBound) in
ByteBufferView`.
Hi @weissi, I checked for CircularBuffer
#2161 _failEarlyRangeCheck
is a no-op as we were validating by use of Index.isValidIndex()
. But in the case of ByteBufferView
, I think we can implement _failEarlyRangeCheck
as it can be utilized in the future. My only concern is whether it should have private access
or public access
Edit: I've opened PR #2226 for this issue, at the same time I noticed that swift core has defined all 3 variants of _failEarlyRangeCheck(https://github.com/apple/swift/blob/main/stdlib/public/core/Collection.swift#L711-L734) in the default implementation of Collection
(An indirect parent struct for ByteBufferView
, in the inheritance hierarchy). Adding our own implementation of _failEarlyRangeCheck
doesn't seem advantageous unless we have some plans of owning & customizing(in future) the functioning of _failEarlyRangeCheck
All subtasks here are completed.