Skip to content

Commit aa301aa

Browse files
authored
Merge pull request #25261 from JuliaLang/kf/iterate
Iteration protocol change
2 parents c2030ed + 62fbad2 commit aa301aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+1310
-2006
lines changed

base/abstractarray.jl

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,9 @@ julia> first([1; 2; 3; 4])
284284
```
285285
"""
286286
function first(itr)
287-
state = start(itr)
288-
done(itr, state) && throw(ArgumentError("collection must be non-empty"))
289-
next(itr, state)[1]
287+
x = iterate(itr)
288+
x === nothing && throw(ArgumentError("collection must be non-empty"))
289+
x[1]
290290
end
291291

292292
"""
@@ -635,10 +635,12 @@ emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
635635

636636
function copyto!(dest::AbstractArray, src)
637637
destiter = eachindex(dest)
638-
state = start(destiter)
638+
y = iterate(destiter)
639639
for x in src
640-
i, state = next(destiter, state)
641-
dest[i] = x
640+
y === nothing &&
641+
throw(ArgumentError(string("source has fewer elements than required")))
642+
dest[y[1]] = x
643+
y = iterate(destiter, y[2])
642644
end
643645
return dest
644646
end
@@ -657,25 +659,24 @@ function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
657659
if (sstart < 1)
658660
throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
659661
end
660-
st = start(src)
662+
y = iterate(src)
661663
for j = 1:(sstart-1)
662-
if done(src, st)
664+
if y === nothing
663665
throw(ArgumentError(string("source has fewer elements than required, ",
664666
"expected at least ",sstart,", got ",j-1)))
665667
end
666-
_, st = next(src, st)
668+
y = iterate(src, y[2])
667669
end
668-
dn = done(src, st)
669-
if dn
670+
if y === nothing
670671
throw(ArgumentError(string("source has fewer elements than required, ",
671672
"expected at least ",sstart,", got ",sstart-1)))
672673
end
673674
i = Int(dstart)
674-
while !dn
675-
val, st = next(src, st)
675+
while y != nothing
676+
val, st = y
676677
dest[i] = val
677678
i += 1
678-
dn = done(src, st)
679+
y = iterate(src, st)
679680
end
680681
return dest
681682
end
@@ -690,18 +691,19 @@ function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::
690691
sstart < 1 && throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
691692
throw(BoundsError(dest, dstart:dmax))
692693
end
693-
st = start(src)
694+
y = iterate(src)
694695
for j = 1:(sstart-1)
695-
if done(src, st)
696+
if y === nothing
696697
throw(ArgumentError(string("source has fewer elements than required, ",
697698
"expected at least ",sstart,", got ",j-1)))
698699
end
699-
_, st = next(src, st)
700+
y = iterate(src, y[2])
700701
end
701702
i = Int(dstart)
702-
while i <= dmax && !done(src, st)
703-
val, st = next(src, st)
703+
while i <= dmax && y !== nothing
704+
val, st = y
704705
@inbounds dest[i] = val
706+
y = iterate(src, st)
705707
i += 1
706708
end
707709
i <= dmax && throw(BoundsError(dest, i))
@@ -823,9 +825,11 @@ zero(x::AbstractArray{T}) where {T} = fill!(similar(x), zero(T))
823825
# While the definitions for IndexLinear are all simple enough to inline on their
824826
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
825827
# inlining.
826-
start(A::AbstractArray) = (@_inline_meta; itr = eachindex(A); (itr, start(itr)))
827-
next(A::AbstractArray, i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2]); (A[idx], (i[1], s)))
828-
done(A::AbstractArray, i) = (@_propagate_inbounds_meta; done(i[1], i[2]))
828+
function iterate(A::AbstractArray, state=(eachindex(A),))
829+
y = iterate(state...)
830+
y === nothing && return nothing
831+
A[y[1]], (state[1], tail(y)...)
832+
end
829833

830834
isempty(a::AbstractArray) = (_length(a) == 0)
831835

@@ -2042,12 +2046,17 @@ function hash(a::AbstractArray{T}, h::UInt) where T
20422046
h += hashaa_seed
20432047
h += hash(size(a))
20442048

2045-
state = start(a)
2046-
done(a, state) && return h
2047-
x1, state = next(a, state)
2048-
done(a, state) && return hash(x1, h)
2049-
x2, state = next(a, state)
2050-
done(a, state) && return hash(x2, hash(x1, h))
2049+
y1 = iterate(a)
2050+
y1 === nothing && return h
2051+
y2 = iterate(a, y1[2])
2052+
y2 === nothing && return hash(y1[1], h)
2053+
y = iterate(a, y2[2])
2054+
y === nothing && return hash(y2[1], hash(y1[1], h))
2055+
x1, x2 = y1[1], y2[1]
2056+
2057+
# For the rest of the function, we keep three elements worth of state,
2058+
# x1, x2, y[1], with `y` potentially being `nothing` if there's only
2059+
# two elements remaining
20512060

20522061
# Check whether the array is equal to a range, and hash the elements
20532062
# at the beginning of the array as such as long as they match this assumption
@@ -2056,6 +2065,10 @@ function hash(a::AbstractArray{T}, h::UInt) where T
20562065
if isa(a, AbstractVector) && applicable(-, x2, x1)
20572066
n = 1
20582067
local step, laststep, laststate
2068+
2069+
h = hash(x1, h)
2070+
h += hashr_seed
2071+
20592072
while true
20602073
# If overflow happens with entries of the same type, a cannot be equal
20612074
# to a range with more than two elements because more extreme values
@@ -2077,47 +2090,48 @@ function hash(a::AbstractArray{T}, h::UInt) where T
20772090
end
20782091
n > 1 && !isequal(step, laststep) && break
20792092
n += 1
2080-
x1 = x2
20812093
laststep = step
2082-
laststate = state
2083-
done(a, state) && break
2084-
x2, state = next(a, state)
2094+
if y === nothing
2095+
# The array matches a range exactly
2096+
return hash(x2, hash(n, h))
2097+
end
2098+
x1, x2 = x2, y[1]
2099+
y = iterate(a, y[2])
20852100
end
20862101

2087-
h = hash(first(a), h)
2088-
h += hashr_seed
20892102
# Always hash at least the two first elements as a range (even in case of overflow)
20902103
if n < 2
20912104
h = hash(2, h)
2092-
h = hash(x2, h)
2093-
done(a, state) && return h
2094-
x1 = x2
2095-
x2, state = next(a, state)
2105+
h = hash(y2[1], h)
2106+
@assert y !== nothing
2107+
x1, x2 = x2, y[1]
2108+
y = iterate(a, y[2])
20962109
else
20972110
h = hash(n, h)
20982111
h = hash(x1, h)
2099-
done(a, laststate) && return h
21002112
end
21012113
end
21022114

2103-
# Hash elements which do not correspond to a range (if any)
2115+
# Hash elements which do not correspond to a range
21042116
while true
21052117
if isequal(x2, x1)
21062118
# For repeated elements, use run length encoding
21072119
# This allows efficient hashing of sparse arrays
21082120
runlength = 2
2109-
while !done(a, state)
2110-
x2, state = next(a, state)
2121+
while y !== nothing
2122+
# No need to update x1 (it's isequal x2)
2123+
x2 = y[1]
2124+
y = iterate(a, y[2])
21112125
isequal(x1, x2) || break
21122126
runlength += 1
21132127
end
21142128
h += hashrle_seed
21152129
h = hash(runlength, h)
21162130
end
21172131
h = hash(x1, h)
2118-
done(a, state) && break
2119-
x1 = x2
2120-
x2, state = next(a, state)
2132+
y === nothing && break
2133+
x1, x2 = x2, y[1]
2134+
y = iterate(a, y[2])
21212135
end
21222136
!isequal(x2, x1) && (h = hash(x2, h))
21232137
return h

base/abstractdict.jl

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,10 @@ isempty(v::Union{KeySet,ValueIterator}) = isempty(v.dict)
5555
_tt2(::Type{Pair{A,B}}) where {A,B} = B
5656
eltype(::Type{ValueIterator{D}}) where {D} = _tt2(eltype(D))
5757

58-
start(v::Union{KeySet,ValueIterator}) = start(v.dict)
59-
done(v::Union{KeySet,ValueIterator}, state) = done(v.dict, state)
60-
61-
function next(v::KeySet, state)
62-
n = next(v.dict, state)
63-
n[1][1], n[2]
64-
end
65-
66-
function next(v::ValueIterator, state)
67-
n = next(v.dict, state)
68-
n[1][2], n[2]
58+
function iterate(v::Union{KeySet,ValueIterator}, state...)
59+
y = iterate(v.dict, state...)
60+
y === nothing && return nothing
61+
return (y[1][isa(v, KeySet) ? 1 : 2], y[2])
6962
end
7063

7164
in(k, v::KeySet) = get(v.dict, k, secret_table_token) !== secret_table_token
@@ -670,9 +663,11 @@ end
670663

671664
_oidd_nextind(a, i) = reinterpret(Int, ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i))
672665

673-
start(d::IdDict) = _oidd_nextind(d.ht, 0)
674-
done(d::IdDict, i) = (i == -1)
675-
next(d::IdDict{K, V}, i) where {K, V} = (Pair{K, V}(d.ht[i + 1]::K, d.ht[i + 2]::V), _oidd_nextind(d.ht, i + 2))
666+
function iterate(d::IdDict{K,V}, idx=0) where {K, V}
667+
idx = _oidd_nextind(d.ht, idx)
668+
idx == -1 && return nothing
669+
return (Pair{K, V}(d.ht[idx + 1]::K, d.ht[idx + 2]::V), idx + 2)
670+
end
676671

677672
length(d::IdDict) = d.count
678673

@@ -711,9 +706,9 @@ empty!(s::IdSet) = (empty!(s.dict); s)
711706

712707
filter!(f, d::IdSet) = unsafe_filter!(f, d)
713708

714-
start(s::IdSet) = start(s.dict)
715-
done(s::IdSet, state) = done(s.dict, state)
716-
function next(s::IdSet, state)
717-
((k, _), i) = next(s.dict, state)
709+
function iterate(s::IdSet, state...)
710+
y = iterate(s.dict, state...)
711+
y === nothing && return nothing
712+
((k, _), i) = y
718713
return (k, i)
719714
end

0 commit comments

Comments
 (0)