swift-nio icon indicating copy to clipboard operation
swift-nio copied to clipboard

ByteBufferView: implement most Collection/Sequence customisation points

Open weissi opened this issue 5 years ago • 6 comments

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

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

weissi avatar Feb 06 '20 11:02 weissi

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 avatar Feb 26 '20 03:02 trungducc

@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 avatar Feb 26 '20 10:02 weissi

@weissi Oh yes. That makes sense. I didn't think about it. Thank you for pointing out!

trungducc avatar Feb 26 '20 11:02 trungducc

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.

Lukasa avatar Feb 07 '22 12:02 Lukasa

_customContainsEquatableElement was done in https://github.com/apple/swift-nio/pull/2044

glbrntt avatar Feb 09 '22 13:02 glbrntt

@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`.

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

anishagg17 avatar Jul 23 '22 21:07 anishagg17

All subtasks here are completed.

Lukasa avatar Apr 24 '23 10:04 Lukasa