diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6367419b..af5b2447 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,7 @@ jobs: version: - '1.6' - '1' + - '~1.9.0-0' os: - ubuntu-latest - macOS-latest diff --git a/Project.toml b/Project.toml index 245580c7..0399075e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FillArrays" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.13.6" +version = "0.13.7" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/FillArrays.jl b/src/FillArrays.jl index 156b928b..2e223101 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -61,6 +61,24 @@ IndexStyle(::Type{<:AbstractFill{<:Any,N,<:NTuple{N,Base.OneTo{Int}}}}) where N issymmetric(F::AbstractFill{<:Any, 2}) = axes(F,1) == axes(F,2) ishermitian(F::AbstractFill{<:Any, 2}) = issymmetric(F) && iszero(imag(getindex_value(F))) +Base.IteratorSize(::Type{<:AbstractFill{T,N,Axes}}) where {T,N,Axes} = _IteratorSize(Axes) +_IteratorSize(::Type{Tuple{}}) = Base.HasShape{0}() +_IteratorSize(::Type{Tuple{T}}) where {T} = Base.IteratorSize(T) +# Julia Base has an optimized any for Tuples on versions >= v1.9 +# On lower versions, a recursive implementation helps with type-inference +if VERSION >= v"1.9.0-beta3" + _any(f, t::Tuple) = any(f, t) +else + _any(f, ::Tuple{}) = false + _any(f, t::Tuple) = f(t[1]) || _any(f, Base.tail(t)) +end +function _IteratorSize(::Type{T}) where {T<:Tuple} + N = fieldcount(T) + s = ntuple(i-> Base.IteratorSize(fieldtype(T, i)), N) + _any(x -> x isa Base.IsInfinite, s) ? Base.IsInfinite() : Base.HasShape{N}() +end + + """ Fill{T, N, Axes} where {T,N,Axes<:Tuple{Vararg{AbstractUnitRange,N}}} diff --git a/test/infinitearrays.jl b/test/infinitearrays.jl index 9145c956..0b6f62db 100644 --- a/test/infinitearrays.jl +++ b/test/infinitearrays.jl @@ -35,6 +35,8 @@ module InfiniteArrays Base.last(r::AbstractInfUnitRange) = Infinity() Base.axes(r::AbstractInfUnitRange) = (OneToInf(),) + Base.IteratorSize(::Type{<:AbstractInfUnitRange}) = Base.IsInfinite() + """ OneToInf(n) Define an `AbstractInfUnitRange` that behaves like `1:∞`, with the added diff --git a/test/runtests.jl b/test/runtests.jl index 77923378..46272a80 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -638,10 +638,20 @@ end @test_throws UndefKeywordError cumsum(Fill(1,1,5)) @testset "infinite arrays" begin - A = Ones{Int}((InfiniteArrays.OneToInf(),)) + r = InfiniteArrays.OneToInf() + A = Ones{Int}((r,)) @test isinf(sum(A)) @test sum(A) == length(A) @test sum(x->x^2, A) == sum(A.^2) + @testset "IteratorSize" begin + @test (@inferred Base.IteratorSize(Ones())) == Base.IteratorSize(ones()) + @test (@inferred Base.IteratorSize(Ones(2))) == Base.IteratorSize(ones(2)) + @test (@inferred Base.IteratorSize(Ones(r))) == Base.IsInfinite() + @test (@inferred Base.IteratorSize(Fill(2, (1:2, 1:2)))) == Base.HasShape{2}() + @test (@inferred Base.IteratorSize(Fill(2, (1:2, r)))) == Base.IsInfinite() + @test (@inferred Base.IteratorSize(Fill(2, (r, 1:2)))) == Base.IsInfinite() + @test (@inferred Base.IteratorSize(Fill(2, (r, r)))) == Base.IsInfinite() + end end end