diff --git a/Project.toml b/Project.toml index 68d7765..e730c7a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "StridedViews" uuid = "4db3bf67-4bd7-4b4e-b153-31dc3fb37143" authors = ["Lukas Devos ", "Jutho Haegeman "] -version = "0.5.4" +version = "0.5.5" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/StridedViews.jl b/src/StridedViews.jl index dc2e1c2..6bf1d5e 100644 --- a/src/StridedViews.jl +++ b/src/StridedViews.jl @@ -6,6 +6,9 @@ const SliceIndex = Union{RangeIndex, Colon} using LinearAlgebra export StridedView, sreshape, sview, isstrided +@static if VERSION >= v"1.11.0-DEV.469" + eval(Expr(:public, :unsafe_stridedview)) +end include("auxiliary.jl") include("stridedview.jl") diff --git a/src/stridedview.jl b/src/stridedview.jl index ac5dea3..a996aac 100644 --- a/src/stridedview.jl +++ b/src/stridedview.jl @@ -39,28 +39,36 @@ function StridedView( size::NTuple{N, Int} = size(parent), strides::NTuple{N, Int} = strides(parent), offset::Int = 0, - op::F = identity; - normalize::Bool = true + op::F = identity ) where {N, F} T = Base.promote_op(op, eltype(parent)) - return StridedView{T}(parent, size, strides, offset, op; normalize) + return StridedView{T}(parent, size, strides, offset, op) end function StridedView{T}( parent::DenseArray, size::NTuple{N, Int} = size(parent), strides::NTuple{N, Int} = strides(parent), offset::Int = 0, - op::F = identity; - normalize::Bool = true + op::F = identity ) where {T, N, F} - # `normalize = false` asserts that `parent` and `strides` are already normalized, - # e.g. because they are taken from an existing `StridedView`. - normalize || return StridedView{T, N, typeof(parent), F}(parent, size, strides, offset, op) parent′ = _normalizeparent(parent) strides′ = _normalizestrides(size, strides) return StridedView{T, N, typeof(parent′), F}(parent′, size, strides′, offset, op) end +""" + unsafe_stridedview(T, parent, size, strides, offset, op) + +Construct a `StridedView{T}` without normalizing `parent` and `strides`, which are assumed to +be normalized already, e.g. because they are taken from an existing `StridedView`. +""" +function unsafe_stridedview( + ::Type{T}, parent::DenseArray, size::NTuple{N, Int}, strides::NTuple{N, Int}, + offset::Int, op::F + ) where {T, N, F} + return StridedView{T, N, typeof(parent), F}(parent, size, strides, offset, op) +end + StridedView(a::StridedView) = a StridedView(a::Adjoint) = StridedView(a')' StridedView(a::Transpose) = transpose(StridedView(transpose(a))) @@ -76,10 +84,7 @@ function StridedView(a::Base.ReinterpretArray{T, N}) where {T, N} throw(ArgumentError("Cannot create StridedView with reinterpretation from $S to $T")) b.op isa FN || throw(ArgumentError("Cannot create StridedView with reinterpretation from view with non-identity operation")) - return StridedView{T}( - b.parent, size(b), strides(b), offset(b), identity; - normalize = false - ) + return unsafe_stridedview(T, b.parent, size(b), strides(b), offset(b), identity) end # trait @@ -150,13 +155,9 @@ end function Base.getindex(a::StridedView{T, N}, I::Vararg{SliceIndex, N}) where {T, N} newsize = _computeviewsize(a.size, I) newstrides = _normalizestrides(newsize, _computeviewstrides(a.strides, I)) - return StridedView{T}( - a.parent, - newsize, - newstrides, - a.offset + _computeviewoffset(a.strides, I), - a.op; - normalize = false + return unsafe_stridedview( + T, a.parent, newsize, newstrides, + a.offset + _computeviewoffset(a.strides, I), a.op ) end @@ -182,29 +183,20 @@ end Base.conj(a::StridedView{<:Real}) = a function Base.conj(a::StridedView{T}) where {T <: Complex} newop = _conj(a.op) - return StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ) + return unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop) end function Base.conj(a::StridedView) S = Base.promote_op(a.op, eltype(a)) newop = _conj(a.op) T = Base.promote_op(newop, S) - return StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ) + return unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop) end function Base.permutedims(a::StridedView{T, N}, p) where {T, N} _isperm(N, p) || throw(ArgumentError("Invalid permutation of length $N: $p")) newsize = ntuple(n -> size(a, p[n]), Val(N)) newstrides = ntuple(n -> stride(a, p[n]), Val(N)) - return StridedView{T}( - a.parent, newsize, _normalizestrides(newsize, newstrides), a.offset, a.op; - normalize = false - ) + return unsafe_stridedview(T, a.parent, newsize, _normalizestrides(newsize, newstrides), a.offset, a.op) end LinearAlgebra.transpose(a::StridedView{<:Number, 2}) = permutedims(a, (2, 1)) @@ -214,10 +206,7 @@ function LinearAlgebra.adjoint(a::StridedView{<:Any, 2}) # act recursively, like newop = _adjoint(a.op) T = Base.promote_op(newop, S) return permutedims( - StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ), (2, 1) + unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop), (2, 1) ) end function LinearAlgebra.transpose(a::StridedView{<:Any, 2}) # act recursively, like Base @@ -225,10 +214,7 @@ function LinearAlgebra.transpose(a::StridedView{<:Any, 2}) # act recursively, li newop = _transpose(a.op) T = Base.promote_op(newop, S) return permutedims( - StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ), (2, 1) + unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop), (2, 1) ) end @@ -238,26 +224,17 @@ Base.map(::FA, a::StridedView{<:Number}) = conj(a) function Base.map(::FC, a::StridedView) T = Base.promote_op(conj, eltype(a)) newop = _conj(a.op) - return StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ) + return unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop) end function Base.map(::FT, a::StridedView) T = Base.promote_op(transpose, eltype(a)) newop = _transpose(a.op) - return StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ) + return unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop) end function Base.map(::FA, a::StridedView) T = Base.promote_op(adjoint, eltype(a)) newop = _adjoint(a.op) - return StridedView{T}( - a.parent, a.size, a.strides, a.offset, newop; - normalize = false - ) + return unsafe_stridedview(T, a.parent, a.size, a.strides, a.offset, newop) end # Creating or transforming StridedView by slicing @@ -302,10 +279,7 @@ function sreshape(a::StridedView{T}, newsize::Dims) where {T} newstrides = _computereshapestrides(newsize, _simplifydims(size(a), strides(a))...) end isnothing(newstrides) && throw(ReshapeException(newsize, size(a), strides(a))) - return StridedView{T}( - a.parent, newsize, _normalizestrides(newsize, newstrides), a.offset, a.op; - normalize = false - ) + return unsafe_stridedview(T, a.parent, newsize, _normalizestrides(newsize, newstrides), a.offset, a.op) end sreshape(a::AbstractArray, newsize::Dims) = sreshape(StridedView(a), newsize) diff --git a/test/runtests.jl b/test/runtests.jl index 778f16a..ae42ec0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -234,9 +234,10 @@ if !is_buildkite @test sreshape(B, size(B)) === B @test strides(permutedims(B, (2, 1, 3))) == (1, 1, 4) @test strides(B[1:2:3, :, :]) == (2, 4, 4) - @test StridedView( - B.parent, size(B), strides(B), B.offset, B.op; normalize = false + @test StridedViews.unsafe_stridedview( + eltype(B), B.parent, size(B), strides(B), B.offset, B.op ) === B + @test @inferred(StridedView(A)) == A C = sreshape(B, (2, 1, 1, 4, 1, 1)) @test strides(C) == (1, 2, 2, 2, 8, 8) @test C == reshape(A, (2, 1, 1, 4, 1, 1))