Skip to content

Commit a61ed56

Browse files
authored
Implement is_lazy_wrapper (#290)
* Implement is_forwarding_wrapper trait
1 parent 7bbbfd9 commit a61ed56

File tree

2 files changed

+36
-27
lines changed

2 files changed

+36
-27
lines changed

lib/ArrayInterfaceCore/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ArrayInterfaceCore"
22
uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2"
3-
version = "0.1.9"
3+
version = "0.1.10"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

lib/ArrayInterfaceCore/src/ArrayInterfaceCore.jl

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ const LoTri{T,M} = Union{LowerTriangular{T,M},UnitLowerTriangular{T,M}}
3333
Returns the parent array that type `T` wraps.
3434
"""
3535
parent_type(x) = parent_type(typeof(x))
36-
parent_type(::Type{<:SubArray{T,N,P}}) where {T,N,P} = P
37-
parent_type(::Type{<:Base.ReshapedArray{T,N,P}}) where {T,N,P} = P
38-
parent_type(::Type{Adjoint{T,S}}) where {T,S} = S
39-
parent_type(::Type{Transpose{T,S}}) where {T,S} = S
4036
parent_type(::Type{Symmetric{T,S}}) where {T,S} = S
4137
parent_type(::Type{<:AbstractTriangular{T,S}}) where {T,S} = S
42-
parent_type(::Type{<:PermutedDimsArray{T,N,I1,I2,A}}) where {T,N,I1,I2,A} = A
43-
parent_type(::Type{Base.Slice{T}}) where {T} = T
44-
parent_type(::Type{T}) where {T} = T
45-
parent_type(::Type{R}) where {S,T,A,N,R<:Base.ReinterpretArray{T,N,S,A}} = A
38+
parent_type(@nospecialize T::Type{<:PermutedDimsArray}) = fieldtype(T, :parent)
39+
parent_type(@nospecialize T::Type{<:Adjoint}) = fieldtype(T, :parent)
40+
parent_type(@nospecialize T::Type{<:Transpose}) = fieldtype(T, :parent)
41+
parent_type(@nospecialize T::Type{<:SubArray}) = fieldtype(T, :parent)
42+
parent_type(@nospecialize T::Type{<:Base.ReinterpretArray}) = fieldtype(T, :parent)
43+
parent_type(@nospecialize T::Type{<:Base.ReshapedArray}) = fieldtype(T, :parent)
44+
parent_type(@nospecialize T::Type{<:Union{Base.Slice,Base.IdentityUnitRange}}) = fieldtype(T, :indices)
4645
parent_type(::Type{Diagonal{T,V}}) where {T,V} = V
46+
parent_type(T::Type) = T
4747

4848
"""
4949
buffer(x)
@@ -54,6 +54,18 @@ may not return another array type.
5454
buffer(x) = parent(x)
5555
buffer(x::SparseMatrixCSC) = getfield(x, :nzval)
5656
buffer(x::SparseVector) = getfield(x, :nzval)
57+
buffer(@nospecialize x::Union{Base.Slice,Base.IdentityUnitRange}) = getfield(x, :indices)
58+
59+
"""
60+
is_forwarding_wrapper(::Type{T}) -> Bool
61+
62+
Returns `true` if the type `T` wraps another data type and does not alter any of its
63+
standard interface. For example, if `T` were an array then its size, indices, and elements
64+
would all be equivalent to its wrapped data.
65+
"""
66+
is_forwarding_wrapper(T::Type) = false
67+
is_forwarding_wrapper(@nospecialize T::Type{<:Base.Slice}) = true
68+
is_forwarding_wrapper(@nospecialize x) = is_forwarding_wrapper(typeof(x))
5769

5870
"""
5971
can_change_size(::Type{T}) -> Bool
@@ -62,7 +74,9 @@ Returns `true` if the Base.size of `T` can change, in which case operations
6274
such as `pop!` and `popfirst!` are available for collections of type `T`.
6375
"""
6476
can_change_size(x) = can_change_size(typeof(x))
65-
can_change_size(::Type{T}) where {T} = false
77+
function can_change_size(::Type{T}) where {T}
78+
is_forwarding_wrapper(T) ? can_change_size(parent_type(T)) : false
79+
end
6680
can_change_size(::Type{<:Vector}) = true
6781
can_change_size(::Type{<:AbstractDict}) = true
6882
can_change_size(::Type{<:Base.ImmutableDict}) = false
@@ -123,8 +137,8 @@ end
123137
Query whether a type can use `setindex!`.
124138
"""
125139
can_setindex(x) = can_setindex(typeof(x))
126-
can_setindex(::Type) = true
127-
can_setindex(::Type{<:AbstractRange}) = false
140+
can_setindex(T::Type) = is_forwarding_wrapper(T) ? can_setindex(parent_type(T)) : true
141+
can_setindex(@nospecialize T::Type{<:AbstractRange}) = false
128142
can_setindex(::Type{<:AbstractDict}) = true
129143
can_setindex(::Type{<:Base.ImmutableDict}) = false
130144
can_setindex(@nospecialize T::Type{<:Tuple}) = false
@@ -463,15 +477,10 @@ julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
463477
```
464478
"""
465479
known_first(x) = known_first(typeof(x))
466-
function known_first(::Type{T}) where {T}
467-
if parent_type(T) <: T
468-
return nothing
469-
else
470-
return known_first(parent_type(T))
471-
end
472-
end
473-
known_first(::Type{Base.OneTo{T}}) where {T} = 1
474-
known_first(::Type{<:Base.IdentityUnitRange{T}}) where {T} = known_first(T)
480+
known_first(T::Type) = is_forwarding_wrapper(T) ? known_first(parent_type(T)) : nothing
481+
known_first(::Type{<:Base.OneTo}) = 1
482+
known_first(@nospecialize T::Type{<:LinearIndices}) = 1
483+
known_first(@nospecialize T::Type{<:Base.IdentityUnitRange}) = known_first(parent_type(T))
475484
function known_first(::Type{<:CartesianIndices{N,R}}) where {N,R}
476485
_cartesian_index(ntuple(i -> known_first(R.parameters[i]), Val(N)))
477486
end
@@ -483,16 +492,16 @@ If `last` of an instance of type `T` is known at compile time, return it.
483492
Otherwise, return `nothing`.
484493
485494
```julia
486-
julia> ArrayInterface.known_last(typeof(1:4))
495+
julia> ArrayInterfaceCore.known_last(typeof(1:4))
487496
nothing
488497
489-
julia> ArrayInterface.known_first(typeof(static(1):static(4)))
498+
julia> ArrayInterfaceCore.known_first(typeof(static(1):static(4)))
490499
4
491500
492501
```
493502
"""
494503
known_last(x) = known_last(typeof(x))
495-
known_last(::Type{T}) where {T} = parent_type(T) <: T ? nothing : known_last(parent_type(T))
504+
known_last(T::Type) = is_forwarding_wrapper(T) ? known_last(parent_type(T)) : nothing
496505
function known_last(::Type{<:CartesianIndices{N,R}}) where {N,R}
497506
_cartesian_index(ntuple(i -> known_last(R.parameters[i]), Val(N)))
498507
end
@@ -513,12 +522,12 @@ julia> ArrayInterface.known_step(typeof(1:4))
513522
```
514523
"""
515524
known_step(x) = known_step(typeof(x))
516-
known_step(::Type{T}) where {T} = parent_type(T) <: T ? nothing : known_step(parent_type(T))
525+
known_step(T::Type) = is_forwarding_wrapper(T) ? known_step(parent_type(T)) : nothing
517526
known_step(@nospecialize T::Type{<:AbstractUnitRange}) = 1
518527

519528
"""
520529
is_splat_index(::Type{T}) -> Bool
521-
Returns `static(true)` if `T` is a type that splats across multiple dimensions.
530+
Returns `static(true)` if `T` is a type that splats across multiple dimensions.
522531
"""
523532
is_splat_index(T::Type) = false
524533
is_splat_index(@nospecialize(x)) = is_splat_index(typeof(x))
@@ -536,7 +545,7 @@ ndims_index(::Type{CartesianIndices{0,Tuple{}}}) = 1
536545
ndims_index(@nospecialize T::Type{<:AbstractArray{Bool}}) = ndims(T)
537546
ndims_index(@nospecialize T::Type{<:AbstractArray}) = ndims_index(eltype(T))
538547
ndims_index(@nospecialize T::Type{<:Base.LogicalIndex}) = ndims(fieldtype(T, :mask))
539-
ndims_index(T::DataType) = 1
548+
ndims_index(T::Type) = 1
540549
ndims_index(@nospecialize(i)) = ndims_index(typeof(i))
541550

542551
"""

0 commit comments

Comments
 (0)