Skip to content

Commit eebeaa9

Browse files
authored
More robust iteration over Vectors (#27079)
* 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 ```
1 parent 1b92f51 commit eebeaa9

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

base/array.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ end
642642
## Iteration ##
643643
start(A::Array) = 1
644644
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
645-
done(a::Array,i) = (@_inline_meta; i == length(a)+1)
645+
done(a::Array,i) = (@_inline_meta; i >= length(a)+1)
646646

647647
## Indexing: getindex ##
648648

test/arrayops.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,17 @@ end
24242424
@inferred hash([1,2,3])
24252425
end
24262426

2427+
function f27079()
2428+
X = rand(5)
2429+
for x in X
2430+
resize!(X, 0)
2431+
end
2432+
length(X)
2433+
end
2434+
@testset "iteration over resized vector" begin
2435+
@test f27079() == 0
2436+
end
2437+
24272438
@testset "indices-related shape promotion errors" begin
24282439
@test_throws DimensionMismatch Base.promote_shape((2,), (3,))
24292440
@test_throws DimensionMismatch Base.promote_shape((2, 3), (2, 4))

test/boundscheck_exec.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module TestBoundsCheck
44

5-
using Test, Random
5+
using Test, Random, InteractiveUtils
66

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

242+
# Ensure iteration over arrays is vectorizable with boundschecks off
243+
function g27079(X)
244+
r = 0
245+
@inbounds for x in X
246+
r += x
247+
end
248+
r
249+
end
250+
if bc_opt == bc_default || bc_opt == bc_off
251+
@test occursin("vector.body", sprint(code_llvm, g27079, Tuple{Vector{Int}}))
252+
end
253+
254+
242255
end

0 commit comments

Comments
 (0)