From ffe7bee41af07b69b4eff88023cbe871b8235ce4 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 8 Sep 2025 23:30:40 +0530 Subject: [PATCH 1/5] Accept non-`AbstractArray`s in 2-arg `axes`/`size` --- base/abstractarray.jl | 8 ++++---- test/broadcast.jl | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index d4d430a5a1811..fd5fe521e983c 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -18,7 +18,7 @@ convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T} convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N} """ - size(A::AbstractArray, [dim]) + size(A, [dim]) Return a tuple containing the dimensions of `A`. Optionally you can specify a dimension to just get the length of that dimension. @@ -39,7 +39,7 @@ julia> size(A, 2) 3 ``` """ -size(t::AbstractArray{T,N}, d) where {T,N} = d::Integer <= N ? size(t)[d] : 1 +size(A, d) where {T,N} = d::Integer <= ndims(A) ? size(A)[d] : 1 """ axes(A, d) @@ -72,9 +72,9 @@ ix[2:end] # will work for eg Vector, but may fail in general ix[(begin+1):end] # works for generalized indexes ``` """ -function axes(A::AbstractArray{T,N}, d) where {T,N} +function axes(A, d) @inline - d::Integer <= N ? axes(A)[d] : OneTo(1) + d::Integer <= ndims(A) ? axes(A)[d] : OneTo(1) end """ diff --git a/test/broadcast.jl b/test/broadcast.jl index a751d9d381ce6..38a43cd873ab1 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -1221,3 +1221,11 @@ end @test bc[1] == bc[CartesianIndex(1)] == bc[1, CartesianIndex()] @test a .+ [1 2] == a.a .+ [1 2] end + +@testset "axes/size for a specific broadcasted axis" begin + b = Broadcast.broadcasted(+, ones(2), ones(2,3)) + @test axes(b,1) == 1:2 + @test axes(b,2) == 1:3 + @test size(b,1) == 2 + @test size(b,2) == 3 +end From 26c9e3cff185039c78cbd06815172a32037a8b35 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 9 Sep 2025 23:09:42 +0530 Subject: [PATCH 2/5] length of tuple instead of ndims and restrict to HasShape --- base/abstractarray.jl | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index fd5fe521e983c..45edc3f75347f 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -20,12 +20,18 @@ convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = Abs """ size(A, [dim]) -Return a tuple containing the dimensions of `A`. Optionally you can specify a -dimension to just get the length of that dimension. +Return a tuple containing the dimensions of an `AbstractArray` (or a multidimensional iterator) `A`. +Optionally you may specify a dimension to just get the length of that dimension. + +Non-`AbstractArray` arguments `A` to the two-argument `size` must satisfy +`Base.IteratorSize(A) isa Base.HasShape`. Note that `size` may not be defined for arrays with non-standard indices, in which case [`axes`](@ref) may be useful. See the manual chapter on [arrays with custom indices](@ref man-custom-indices). +!!! compat "Julia 1.13" + `size(A, d)` where `A` is not an `AbstractArray` requires at least Julia 1.13. + See also: [`length`](@ref), [`ndims`](@ref), [`eachindex`](@ref), [`sizeof`](@ref). # Examples @@ -39,12 +45,24 @@ julia> size(A, 2) 3 ``` """ -size(A, d) where {T,N} = d::Integer <= ndims(A) ? size(A)[d] : 1 +function size(A, d) + @inline + _size(IteratorSize(A), size(A), d) +end +function _size(::HasShape, s::Tuple, d::Integer) + @inline + d_Int = convert(Int, d) + d_Int <= length(s) ? s[d_Int] : 1 +end """ axes(A, d) -Return the valid range of indices for array `A` along dimension `d`. +Return the valid range of indices for an `AbstractArray` (or a mutidimensional iterator) +`A` along dimension `d`. + +Non-`AbstractArray` arguments `A` to the two-argument `axes` must satisfy +`Base.IteratorSize(A) isa Base.HasShape`. See also [`size`](@ref), and the manual chapter on [arrays with custom indices](@ref man-custom-indices). @@ -66,6 +84,9 @@ Each of the indices has to be an `AbstractUnitRange{<:Integer}`, but at the same a type that uses custom indices. So, for example, if you need a subset, use generalized indexing constructs like `begin`/`end` or [`firstindex`](@ref)/[`lastindex`](@ref): +!!! compat "Julia 1.13" + `axes(A, d)` where `A` is not an `AbstractArray` requires at least Julia 1.13. + ```julia ix = axes(v, 1) ix[2:end] # will work for eg Vector, but may fail in general @@ -73,8 +94,13 @@ ix[(begin+1):end] # works for generalized indexes ``` """ function axes(A, d) + @inline + _axes(IteratorSize(A), axes(A), d) +end +function _axes(::HasShape, ax::Tuple, d::Integer) @inline - d::Integer <= ndims(A) ? axes(A)[d] : OneTo(1) + d_Int = convert(Int, d) + d_Int <= length(ax) ? ax[d_Int] : OneTo(1) end """ From 0a7acd99c800c1e99b4742488753d6c48efa497b Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 9 Sep 2025 23:11:13 +0530 Subject: [PATCH 3/5] Trailing whitespace --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 45edc3f75347f..9dcf4d5bec350 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -95,7 +95,7 @@ ix[(begin+1):end] # works for generalized indexes """ function axes(A, d) @inline - _axes(IteratorSize(A), axes(A), d) + _axes(IteratorSize(A), axes(A), d) end function _axes(::HasShape, ax::Tuple, d::Integer) @inline From 96f38ab75340f3f9796a7900be1fbb30f1741bdc Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 9 Sep 2025 23:27:04 +0530 Subject: [PATCH 4/5] Update base/abstractarray.jl `Int` constructor instead of convert in `size` Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com> --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9dcf4d5bec350..001f21c7023b4 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -51,7 +51,7 @@ function size(A, d) end function _size(::HasShape, s::Tuple, d::Integer) @inline - d_Int = convert(Int, d) + d_Int = Int(d)::Int d_Int <= length(s) ? s[d_Int] : 1 end From 63a15d513e2c08a193e63215f64080a55ae5a055 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 9 Sep 2025 23:27:15 +0530 Subject: [PATCH 5/5] Update base/abstractarray.jl `Int` constructor instead of convert in `axes` Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com> --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 001f21c7023b4..f3fd279ab84d2 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -99,7 +99,7 @@ function axes(A, d) end function _axes(::HasShape, ax::Tuple, d::Integer) @inline - d_Int = convert(Int, d) + d_Int = Int(d)::Int d_Int <= length(ax) ? ax[d_Int] : OneTo(1) end