Skip to content

Commit

Permalink
Support offset axes in reinterpret
Browse files Browse the repository at this point in the history
The first axis of the input must start with 1. The remaining axes
can be arbitrary.
  • Loading branch information
timholy committed Jul 9, 2018
1 parent b6f9244 commit da88fad
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
15 changes: 14 additions & 1 deletion base/reinterpretarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ struct ReinterpretArray{T,N,S,A<:AbstractArray{S, N}} <: AbstractArray{T, N}
The resulting array would have non-integral first dimension.
"""))
end
function throwaxes1(::Type{S}, ::Type{T}, ax1)
@_noinline_meta
throw(ArgumentError("cannot reinterpret a `$(S)` array to `$(T)` when the first axis is $ax1. Try reshaping first."))
end
isbitstype(T) || throwbits(S, T, T)
isbitstype(S) || throwbits(S, T, S)
(N != 0 || sizeof(T) == sizeof(S)) || throwsize0(S, T)
ax1 = axes(a)[1]
if N != 0 && sizeof(S) != sizeof(T)
dim = size(a)[1]
dim = _length(ax1)
rem(dim*sizeof(S),sizeof(T)) == 0 || thrownonint(S, T, dim)
first(ax1) == 1 || throwaxes1(S, T, ax1)
end
readable = array_subpadding(T, S)
writable = array_subpadding(S, T)
Expand Down Expand Up @@ -69,6 +75,13 @@ function size(a::ReinterpretArray{T,N,S} where {N}) where {T,S}
tuple(size1, tail(psize)...)
end

function axes(a::ReinterpretArray{T,N,S} where {N}) where {T,S}
paxs = axes(a.parent)
f, l = first(paxs[1]), _length(paxs[1])
size1 = div(l*sizeof(S), sizeof(T))
tuple(oftype(paxs[1], f:f+size1-1), tail(paxs)...)
end

elsize(::Type{<:ReinterpretArray{T}}) where {T} = sizeof(T)
unsafe_convert(::Type{Ptr{T}}, a::ReinterpretArray{T,N,S} where N) where {T,S} = Ptr{T}(unsafe_convert(Ptr{S},a.parent))

Expand Down
36 changes: 36 additions & 0 deletions test/reinterpretarray.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Test
isdefined(Main, :TestHelpers) || @eval Main include("TestHelpers.jl")
using .Main.TestHelpers.OAs

A = Int64[1, 2, 3, 4]
B = Complex{Int64}[5+6im, 7+8im, 9+10im]
Expand Down Expand Up @@ -87,3 +89,37 @@ A2 = S2[S2(0, 0)]
@test_throws Base.PaddingError reinterpret(S2, A1)[1]
reinterpret(S2, A1)[1] = S2(1, 2)
@test A1[1] == S1(1, 2)

# Unconventional axes
let a = [0.1 0.2; 0.3 0.4], at = reshape([(i,i+1) for i = 1:2:8], 2, 2)
v = OffsetArray(a, (-1, 1))
r = reinterpret(Int64, v)
@test axes(r) === axes(v)
@test r[0,2] === reinterpret(Int64, v[0,2])
@test r[1,2] === reinterpret(Int64, v[1,2])
@test r[0,3] === reinterpret(Int64, v[0,3])
@test r[1,3] === reinterpret(Int64, v[1,3])
@test_throws ArgumentError("cannot reinterpret a `Float64` array to `UInt32` when the first axis is Base.Slice(0:1). Try reshaping first.") reinterpret(UInt32, v)
v = OffsetArray(a, (0, 1))
r = reinterpret(UInt32, v)
axsv = axes(v)
@test axes(r) === (oftype(axsv[1], 1:4), axsv[2])
for i = 1:2
rval = reinterpret(Tuple{UInt32,UInt32}, [v[i,2]])[1]
@test r[2i-1,2] == rval[1]
@test r[2i,2] == rval[2]
rval = reinterpret(Tuple{UInt32,UInt32}, [v[i,3]])[1]
@test r[2i-1,3] == rval[1]
@test r[2i,3] == rval[2]
end
r[4,2] = 7
@test r[4,2] === UInt32(7)
@test a[2,1] === reinterpret(Float64, [0x33333333, UInt32(7)])[1]
offsetvt = (-2, 4)
vt = OffsetArray(at, offsetvt)
istr = string(Int)
@test_throws ArgumentError("cannot reinterpret a `Tuple{$istr,$istr}` array to `$istr` when the first axis is Base.Slice(-1:0). Try reshaping first.") reinterpret(Int, vt)
vt = reshape(vt, 1:1, axes(vt)...)
r = reinterpret(Int, vt)
@test r == OffsetArray(reshape(1:8, 2, 2, 2), (0, offsetvt...))
end

0 comments on commit da88fad

Please sign in to comment.