Skip to content

add convenience wrappers for ccall(:jl_reshape_array,...) #496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
157 changes: 157 additions & 0 deletions src/SArray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,160 @@ end
function promote_rule(::Type{<:SArray{S,T,N,L}}, ::Type{<:SArray{S,U,N,L}}) where {S,T,U,N,L}
SArray{S,promote_type(T,U),N,L}
end

"""
unsafe_packdims(a::Array{T,N}; dims::Integer=1)
Gives an `N-dims`-dimensional Array of `dims`-dimensional SArrays
referencing the same memory as A. The first `dims`` dimensions are packed.
This operation may be unsafe in terms of aliasing analysis:
The compiler might mistakenly assume that the memory holding the two arrays'
contents does not overlap, even though they in fact do alias.
On Julia 1.0.*, this operation is perfectly safe, but this is expected
to change in the future.

See also `reinterpret`, `reshape`, `packdims`, `unpackdims` and `unsafe_unpackdims`.

# Examples
```jldoctest
julia> A = reshape(collect(1:8), (2,2,2))
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 3
2 4

[:, :, 2] =
5 7
6 8

julia> A_pack = unsafe_packdims(A; dims=2)
2-element Array{SArray{Tuple{2,2},Int64,2,4},1}:
[1 3; 2 4]
[5 7; 6 8]

julia> A[2,2,1]=-1; A[2,2,1]==A_pack[1][2,2]
true
```
"""
@noinline function unsafe_packdims(a::Array{T,N}; dims::Integer=1) where {T,N}
isbitstype(T) || error("$(T) is not a bitstype")
0<dims<N || error("Cannot pack $(dims) dimensions of an $(N)-dim Array")
dims=Int(dims)
sz = size(a)
sz_sa = ntuple(i->sz[i], dims)
satype = SArray{Tuple{sz_sa...}, T, dims, prod(sz_sa)}
sz_rest = ntuple(i->sz[dims+i], N-dims)
restype = Array{satype, N-dims}
ccall(:jl_reshape_array, Any, (Any, Any, Any),restype, a, sz_rest)::restype
end


"""
unsafe_unpackdims(A::Array{SArray})
Gives an Array referencing the same memory as A. Its dimension is the sum of the
SArray dimension and dimension of A, where the SArray dimensions are added in front.
The compiler might mistakenly assume that the memory holding the two arrays'
contents does not overlap, even though they in fact do alias.
On Julia 1.0.*, this operation is perfectly safe, but this is expected
to change in the future.

See also `reinterpret`, `reshape`, `packdims`, `unpackdims` and `unsafe_packdims`.

# Examples
```jldoctest
julia> A_pack = zeros(SVector{2,Int32},2)
2-element Array{SArray{Tuple{2},Int32,1,2},1}:
[0, 0]
[0, 0]

julia> A = unsafe_unpackdims(A_pack); A[1,1]=-1; A[2,1]=-2; A_pack
2-element Array{SArray{Tuple{2},Int32,1,2},1}:
[-1, -2]
[0, 0]

julia> A_pack
2-element Array{SArray{Tuple{2},Int32,1,2},1}:
[-1, -2]
[0, 0]
```
"""
@noinline function unsafe_unpackdims(a::Array{SArray{SZT, T, NDIMS, L},N}) where {T,N,SZT,NDIMS,L}
isbitstype(T) || error("$(T) is not a bitstype")
dimres = N+NDIMS
szres = (size(eltype(a))..., size(a)...)
ccall(:jl_reshape_array, Any, (Any, Any, Any),Array{T,dimres}, a, szres)::Array{T, dimres}
end

"""
packdims(a::AbstractArray{T,N}; dims::Integer=1)
Gives an `N-dims`-dimensional AbstractArray of `dims`-dimensional SArrays
referencing the same memory as A. The first `dims`` dimensions are packed.
In some contexts, the result may have suboptimal performance characteristics.

See also `reinterpret`, `reshape`, `unsafe_packdims`, `unpackdims` and `unsafe_unpackdims`.

# Examples
```jldoctest
julia> A = reshape(collect(1:8), (2,2,2))
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 3
2 4

[:, :, 2] =
5 7
6 8

julia> A_pack = packdims(A; dims=2)
2-element reinterpret(SArray{Tuple{2,2},Int64,2,4}, ::Array{Int64,1}):
[1 3; 2 4]
[5 7; 6 8]

julia> A[2,2,1]=-1; A[2,2,1]==A_pack[1][2,2]
true
```
"""
@noinline function packdims(a::AbstractArray{T,N}; dims::Integer=1) where {T,N}
isbitstype(T) || error("$(T) is not a bitstype")
0<dims<N || error("Cannot pack $(dims) dimensions of an $(N)-dim Array")
dims=Int(dims)
sz = size(a)
sz_sa = ntuple(i->sz[i], dims)
satype = SArray{Tuple{sz_sa...}, T, dims, prod(sz_sa)}
sz_rest = ntuple(i->sz[dims+i], N-dims)
return reshape(reinterpret(satype, reshape(a, length(a))), sz_rest)
end


"""
unpackdims(A::AbstractArray{SArray})
Gives an Array referencing the same memory as A. Its dimension is the sum of the
SArray dimension and dimension of A, where the SArray dimensions are added in front.
In some contexts, the result may have suboptimal performance characteristics.


See also `reinterpret`, `reshape`, `packdims`, `unpackdims` and `unsafe_packdims`.

# Examples
```jldoctest
julia> A_pack = zeros(SVector{2,Int32},2)
2-element Array{SArray{Tuple{2},Int32,1,2},1}:
[0, 0]
[0, 0]

julia> A = unpackdims(A_pack); A[1,1]=-1; A[2,1]=-2; A_pack
2-element Array{SArray{Tuple{2},Int32,1,2},1}:
[-1, -2]
[0, 0]

julia> A
2×2 reshape(reinterpret(Int32, ::Array{SArray{Tuple{2},Int32,1,2},1}), 2, 2) with eltype Int32:
-1 0
-2 0
```
"""
@noinline function unpackdims(a::AbstractArray{SArray{SZT, T, NDIMS, L},N}) where {T,N,SZT,NDIMS,L}
isbitstype(T) || error("$(T) is not a bitstype")
dimres = N+NDIMS
szres = (size(eltype(a))..., size(a)...)
return reshape(reinterpret(T, a),szres)
end
1 change: 1 addition & 0 deletions src/StaticArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export @MVector, @MMatrix, @MArray

export similar_type
export push, pop, pushfirst, popfirst, insert, deleteat, setindex
export packdims, unpackdims, unsafe_packdims, unsafe_unpackdims

"""
abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end
Expand Down