-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
This issue came about when I discovered that sort! on a small vector of integers was slower than usual; further inspection shows that extrema is now 65% slower for a vector of 500 integers, and this is a result of bounds checks in each iteration.
I would not dare to fix this by adding @inbounds to the loop of extrema, since the function is defined for iterators in general (why is it extrema's responsibility to signal that the internals of the iterator will do inbounds things?). I'd say an iterator over an array should guarantee to stay inbounds and not require its call site to provide @inbounds.
But the issue is quite subtle. The function iterate(A::Array, ::Int) does something that comes close to bounds checking
function iterate(A::Array, i=1)
@_propagate_inbounds_meta # why require the parent function to provide inbounds
i >= length(A) + 1 ? nothing : (A[i], i+1) # when we here (kinda) assert we are inbounds?
endbut it's not entirely bounds checking, because in principle i could overflow, so to be safe an actual check is required to guarantee i > 0.
The issue is a result of #27079 (more robust iteration over vectors), but in fact it cheats a bit by requiring the user to always provide Edit (sorry!): without inbounds @inbounds.for x in xs would do bounds checking already.
Possible solutions:
- Create a wrapper
for x in Mutable(xs)that allows to modifyxson the go;for x in xsis then immutable iteration by convention and can be fast even without@inbounds. - Create a separate implementation of
extrema(::AbstractArray)that uses@inbounds(meh) - Just use
@inboundsinextremaand document that it does that - Improve the speed of
checkbounds(Bool, ::AbstractArray, ::Int)and use that rather than thei >= length(A) + 1condition, and somehow tell the compilericannot overflow, so that thei > 0check can be optimized away.
Edit, seems like the new iteration protocol is enough to fix things.