Skip to content

Commit

Permalink
More robust iteration over Vectors (#27079)
Browse files Browse the repository at this point in the history
* More robust iteration over Vectors

Currently, if a vector is resized in the midst of iteration, then `done` might "miss" the end of iteration. This trivially changes the definition to catch such a case. I am not sure what guarantees we make about mutating iterables during iteration, but this seems simple and easy to support.  Note, though, that it is somewhat tricky: until #13866 we used `i > length(a)`, but that foils vectorization due to the `typemax` case. This definition seems to get the best of both worlds. For a definition like `f` below, this new definition just requires one extra `add i64` operation in the preamble (before the loop). Everything else is identical to master.

```julia
function f(A)
    r = 0
    @inbounds for x in A
        r += x
    end
    r
end
```
  • Loading branch information
mbauman authored May 15, 2018
1 parent 1b92f51 commit eebeaa9
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
2 changes: 1 addition & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ end
## Iteration ##
start(A::Array) = 1
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
done(a::Array,i) = (@_inline_meta; i == length(a)+1)
done(a::Array,i) = (@_inline_meta; i >= length(a)+1)

## Indexing: getindex ##

Expand Down
11 changes: 11 additions & 0 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2424,6 +2424,17 @@ end
@inferred hash([1,2,3])
end

function f27079()
X = rand(5)
for x in X
resize!(X, 0)
end
length(X)
end
@testset "iteration over resized vector" begin
@test f27079() == 0
end

@testset "indices-related shape promotion errors" begin
@test_throws DimensionMismatch Base.promote_shape((2,), (3,))
@test_throws DimensionMismatch Base.promote_shape((2, 3), (2, 4))
Expand Down
15 changes: 14 additions & 1 deletion test/boundscheck_exec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module TestBoundsCheck

using Test, Random
using Test, Random, InteractiveUtils

@enum BCOption bc_default bc_on bc_off
bc_opt = BCOption(Base.JLOptions().check_bounds)
Expand Down Expand Up @@ -239,4 +239,17 @@ if bc_opt != bc_off
@test_throws BoundsError BadVector20469([1,2,3])[:]
end

# Ensure iteration over arrays is vectorizable with boundschecks off
function g27079(X)
r = 0
@inbounds for x in X
r += x
end
r
end
if bc_opt == bc_default || bc_opt == bc_off
@test occursin("vector.body", sprint(code_llvm, g27079, Tuple{Vector{Int}}))
end


end

0 comments on commit eebeaa9

Please sign in to comment.