Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ 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.
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
Expand All @@ -39,12 +45,24 @@ julia> size(A, 2)
3
```
"""
size(t::AbstractArray{T,N}, d) where {T,N} = d::Integer <= N ? size(t)[d] : 1
function size(A, d)
@inline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are this @inline, and other @inlines, actually necessary? Generally I think it's better to leave the inlining to the compiler in generic methods, except maybe for recursive methods, or as a workaround for issue #53584/#56587.

Suggested change
@inline

_size(IteratorSize(A), size(A), d)
end
function _size(::HasShape, s::Tuple, d::Integer)
@inline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@inline

d_Int = Int(d)::Int
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).

Expand All @@ -66,15 +84,23 @@ 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
ix[(begin+1):end] # works for generalized indexes
```
"""
function axes(A::AbstractArray{T,N}, d) where {T,N}
function axes(A, d)
@inline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@inline

_axes(IteratorSize(A), axes(A), d)
end
function _axes(::HasShape, ax::Tuple, d::Integer)
@inline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@inline

d::Integer <= N ? axes(A)[d] : OneTo(1)
d_Int = Int(d)::Int
d_Int <= length(ax) ? ax[d_Int] : OneTo(1)
end

"""
Expand Down
8 changes: 8 additions & 0 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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