Skip to content

Commit 8e76592

Browse files
committed
* decouple nth from first and drop, by manually write the unrolled version of first(drop(itr, n-1))
* uniform the errors to be just `BoundsErrors`, instead of parrotting the cryptic "collection must be non empty" arising from the interplay between `first` and `drop`. * This would allow defining the generic `first` in terms of `nth(itr, 1)` in the future maybe * add check to prevent negative `n` in the cycle version, inheriting the error from the base version * adds propagate inbounds for the array version
1 parent 320a7d4 commit 8e76592

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

base/iterators.jl

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,33 +1630,46 @@ nth(itr, n::Integer) = _nth(itr, n)
16301630

16311631
# infinite cycle
16321632
function nth(itr::Cycle{I}, n::Integer) where {I}
1633-
n < 0 && throw(ArgumentError("Drop length must be non-negative"))
1634-
16351633
if IteratorSize(I) isa Union{HasShape, HasLength}
16361634
N = length(itr.xs)
1637-
N > 0 ? _nth(itr.xs, mod1(n, N)) : throw(ArgumentError("collection must be non-empty"))
1635+
N == 0 && throw(BoundsError(itr, n))
1636+
1637+
# prevent wrap around behaviour
1638+
return _nth(itr.xs, ifelse(n > 0, mod1(n, N), n))
16381639
else
1639-
_nth(itr, n)
1640+
return _nth(itr, n)
16401641
end
16411642
end
16421643

16431644
# Flatten{Take{Repeated{O}}} is the actual type of an Iterators.cycle(iterable::O, m) iterator
16441645
function nth(itr::Flatten{Take{Repeated{O}}}, n::Integer) where {O}
1645-
n < 0 && throw(ArgumentError("Drop length must be non-negative"))
1646-
16471646
if IteratorSize(O) isa Union{HasShape, HasLength}
16481647
cycles = itr.it.n
1649-
repeated = itr.it.xs.x
1650-
k = length(repeated)
1651-
n > k*cycles ?
1652-
throw(ArgumentError("collection must be non-empty")) : _nth(repeated, mod1(n, k))
1648+
torepeat = itr.it.xs.x
1649+
k = length(torepeat)
1650+
(n > k*cycles || k == 0) && throw(BoundsError(itr, n))
1651+
1652+
# prevent wrap around behaviour
1653+
return _nth(torepeat, ifelse(n > 0, mod1(n, k), n))
16531654
else
1654-
_nth(itr, n)
1655+
return _nth(itr, n)
1656+
end
1657+
end
1658+
1659+
Base.@propagate_inbounds _nth(itr::AbstractArray, n) = itr[begin + n-1]
1660+
1661+
function _nth(itr, n)
1662+
# unrolled version of `first(drop)`
1663+
n > 0 || throw(ArgumentError("n must be positive"))
1664+
y = iterate(itr)
1665+
for i in 1:n-1
1666+
y === nothing && break
1667+
y = iterate(itr, y[2])
16551668
end
1669+
y === nothing && throw(BoundsError(itr, n))
1670+
y[1]
16561671
end
16571672

1658-
_nth(itr, n) = first(drop(itr, n-1))
1659-
_nth(itr::AbstractArray, n) = itr[begin + n-1]
16601673
"""
16611674
nth(n::Integer)
16621675

0 commit comments

Comments
 (0)