|
1 | 1 | module OffsetArrays |
2 | 2 |
|
3 | | -#import Base: Array |
4 | | -importall Base |
| 3 | +Base.@deprecate_binding (..) Colon() |
5 | 4 |
|
6 | | -export OffsetArray, .. |
| 5 | +using Base: SimIdx, Indices, LinearSlow, LinearFast |
7 | 6 |
|
8 | | -type OffsetArray{T<:Number, N, A<:AbstractArray} <: AbstractArray |
| 7 | +export OffsetArray |
9 | 8 |
|
| 9 | +immutable OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N} |
| 10 | + parent::AA |
10 | 11 | offsets::NTuple{N,Int} |
11 | | - array::A |
12 | | - o1::Int |
13 | | - o2::Int |
14 | | - o3::Int |
15 | | - o4::Int |
16 | | - o5::Int |
17 | | - |
18 | | - function OffsetArray(r::Range1{Int}) |
19 | | - array = Array(T, length(r)) |
20 | | - offs = (1 - minimum(r),) |
21 | | - new(offs, array, offs[1]) |
22 | | - end |
23 | | - |
24 | | - function OffsetArray(r1::Range1{Int}, r2::Range1{Int}) |
25 | | - dims = (length(r1), length(r2)) |
26 | | - array = Array(T, dims) |
27 | | - offs = (1 - minimum(r1), 1 - minimum(r2)) |
28 | | - new(offs, array, offs[1], offs[2]) |
29 | | - end |
30 | | - |
31 | | - function OffsetArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int}) |
32 | | - dims = (length(r1), length(r2), length(r3)) |
33 | | - array = Array(T, dims) |
34 | | - offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3)) |
35 | | - new(offs, array, offs[1], offs[2], offs[3]) |
36 | | - end |
37 | | - |
38 | | - function OffsetArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int}, r4::Range1{Int}) |
39 | | - dims = (length(r1), length(r2), length(r3), length(r4)) |
40 | | - array = Array(T, dims) |
41 | | - offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3), 1 - minimum(r4)) |
42 | | - new(offs, array, offs[1], offs[2], offs[3], offs[4]) |
43 | | - end |
44 | | - |
45 | | - function OffsetArray(r1::Range1{Int}, r2::Range1{Int}, r3::Range1{Int}, r4::Range1{Int}, r5::Range1{Int}) |
46 | | - dims = (length(r1), length(r2), length(r3), length(r4), length(r5)) |
47 | | - array = Array(T, dims) |
48 | | - offs = (1 - minimum(r1), 1 - minimum(r2), 1 - minimum(r3), 1 - minimum(r4), 1 - minimum(r5)) |
49 | | - new(offs, array, offs[1], offs[2], offs[3], offs[4], offs[5]) |
50 | | - end |
51 | | - |
52 | | - function OffsetArray(r::Range1{Int}...) |
53 | | - dims = map((x) -> length(x), r) |
54 | | - array = Array(T, dims) |
55 | | - offs = map((x) -> 1 - minimum(x), r) |
56 | | - new(offs, array) |
57 | | - end |
58 | | - |
| 12 | +end |
| 13 | +typealias OffsetVector{T,AA<:AbstractArray} OffsetArray{T,1,AA} |
| 14 | + |
| 15 | +OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::NTuple{N,Int}) = OffsetArray{T,N,typeof(A)}(A, offsets) |
| 16 | +OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::Vararg{Int,N}) = OffsetArray(A, offsets) |
| 17 | + |
| 18 | +(::Type{OffsetArray{T,N}}){T,N}(inds::Indices{N}) = OffsetArray{T,N,Array{T,N}}(Array{T,N}(map(Base.dimlength, inds)), map(indsoffset, inds)) |
| 19 | +(::Type{OffsetArray{T}}){T,N}(inds::Indices{N}) = OffsetArray{T,N}(inds) |
| 20 | +OffsetArray{T,N}(::Type{T}, inds::Vararg{UnitRange{Int},N}) = OffsetArray{T,N}(inds) |
| 21 | + |
| 22 | +Base.linearindexing{T<:OffsetArray}(::Type{T}) = Base.linearindexing(parenttype(T)) |
| 23 | +Base.indicesbehavior{T<:OffsetArray}(::Type{T}) = Base.IndicesUnitRange() |
| 24 | +parenttype{T,N,AA}(::Type{OffsetArray{T,N,AA}}) = AA |
| 25 | +parenttype(A::OffsetArray) = parenttype(typeof(A)) |
| 26 | + |
| 27 | +Base.parent(A::OffsetArray) = A.parent |
| 28 | +Base.size(A::OffsetArray) = size(parent(A)) |
| 29 | +Base.eachindex(::LinearSlow, A::OffsetArray) = CartesianRange(indices(A)) |
| 30 | +Base.eachindex(::LinearFast, A::OffsetVector) = indices(A, 1) |
| 31 | +Base.summary(A::OffsetArray) = string(typeof(A))*" with indices "*string(indices(A)) |
| 32 | + |
| 33 | +# Implementations of indices and indices1. Since bounds-checking is |
| 34 | +# performance-critical and relies on indices, these are usually worth |
| 35 | +# optimizing thoroughly. |
| 36 | +@inline Base.indices(A::OffsetArray, d) = 1 <= d <= length(A.offsets) ? (o = A.offsets[d]; (1+o:size(parent(A),d)+o)) : (1:1) |
| 37 | +@inline Base.indices(A::OffsetArray) = _indices((), A) # would rather use ntuple, but see #15276 |
| 38 | +@inline _indices{T,N}(out::NTuple{N}, A::OffsetArray{T,N}) = out |
| 39 | +@inline _indices(out, A::OffsetArray) = (d = length(out)+1; o = A.offsets[d]; _indices((out..., (1+o:size(parent(A),d)+o)), A)) |
| 40 | +# By optimizing indices1 we can avoid a branch on the dim-check |
| 41 | +Base.indices1{T}(A::OffsetArray{T,0}) = 1:1 |
| 42 | +@inline Base.indices1(A::OffsetArray) = (o = A.offsets[1]; 1+o:size(parent(A),1)+o) |
| 43 | + |
| 44 | +function Base.similar(A::OffsetArray, T::Type, dims::Dims) |
| 45 | + B = similar(parent(A), T, dims) |
| 46 | +end |
| 47 | +function Base.similar(A::AbstractArray, T::Type, inds::Tuple{Vararg{SimIdx}}) |
| 48 | + B = similar(A, T, map(Base.dimlength, inds)) |
| 49 | + OffsetArray(B, map(indsoffset, inds)) |
59 | 50 | end |
60 | 51 |
|
61 | | -OffsetArray(T, r::Range1{Int}...) = OffsetArray{T, length(r,), Array{T, length(r,)}}(r...) |
62 | | - |
63 | | -getindex{T<:Number}(FA::OffsetArray{T,1}, i1::Int) = FA.array[i1+FA.o1] |
64 | | -getindex{T<:Number}(FA::OffsetArray{T,2}, i1::Int, i2::Int) = FA.array[i1+FA.o1, i2+FA.o2] |
65 | | -getindex{T<:Number}(FA::OffsetArray{T,3}, i1::Int, i2::Int, i3::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3] |
66 | | -getindex{T<:Number}(FA::OffsetArray{T,4}, i1::Int, i2::Int, i3::Int, i4::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4] |
67 | | -getindex{T<:Number}(FA::OffsetArray{T,5}, i1::Int, i2::Int, i3::Int, i4::Int, i5::Int) = FA.array[i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4, i5+FA.o5] |
68 | | - |
69 | | -# a generic but not very efficient case |
70 | | -getindex{T<:Number,N}(FA::OffsetArray{T,N}, I::Int...) = let ind = [I[i] + FA.offsets[i] for i = 1:length(I)]; return FA.array[ind...] end |
71 | | - |
72 | | -setindex!{T<:Number}(FA::OffsetArray{T,1}, x, i1::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1) |
73 | | -setindex!{T<:Number}(FA::OffsetArray{T,2}, x, i1::Int, i2::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2) |
74 | | -setindex!{T<:Number}(FA::OffsetArray{T,3}, x, i1::Int, i2::Int, i3::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3) |
75 | | -setindex!{T<:Number}(FA::OffsetArray{T,4}, x, i1::Int, i2::Int, i3::Int, i4::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4) |
76 | | -setindex!{T<:Number}(FA::OffsetArray{T,5}, x, i1::Int, i2::Int, i3::Int, i4::Int, i5::Int) = arrayset(FA.array, convert(T,x), i1+FA.o1, i2+FA.o2, i3+FA.o3, i4+FA.o4, i5+FA.o5) |
77 | | - |
78 | | -# a generic not very efficient case |
79 | | -setindex!{T<:Number,N}(FA::OffsetArray{T,N}, x, I::Int...) = let ind = [I[i] + FA.offsets[i] for i = 1:length(I)]; arrayset(FA.array, convert(T,x), ind...) end |
80 | | - |
81 | | -Base.print(a::OffsetArray) = Base.print(a.array) |
82 | | -Base.display(a::OffsetArray) = Base.display(a.array) |
83 | | - |
84 | | -Base.size(a::OffsetArray) = arraysize(a.array) |
85 | | -Base.size(a::OffsetArray, d) = arraysize(a.array, d) |
86 | | - |
87 | | - |
88 | | -# as the parser changes colons into ranges. |
89 | | -# for avoiding to write a[Colon()] a whole range .. is introduced |
90 | | -# it is possible to write say a[..] = b[..] |
91 | | - |
92 | | -const (..) = Colon() |
93 | | - |
94 | | -getindex{T<:Number}(FA::OffsetArray{T,1}, r1::Union(Range1{Int},Colon)) = |
95 | | - isa(r1, Colon) ? FA.array[:] : FA.array[r1+FA.o1] |
96 | | - |
97 | | -getindex{T<:Number}(FA::OffsetArray{T,2}, r1::Union(Range1{Int},Colon), i2::Int) = |
98 | | - isa(r1, Colon) ? FA.array[:, i2+FA.o2] : FA.array[r1+FA.o1, i2+FA.o2] |
| 52 | +Base.allocate_for(f, A::OffsetArray, shape::SimIdx) = OffsetArray(f(Base.dimlength(shape)), (indsoffset(shape),)) |
| 53 | +Base.allocate_for(f, A::OffsetArray, shape::Tuple{Vararg{SimIdx}}) = OffsetArray(f(map(Base.dimlength, shape)), map(indsoffset, shape)) |
| 54 | +Base.promote_indices(a::OffsetArray, b::OffsetArray) = a |
99 | 55 |
|
100 | | -getindex{T<:Number}(FA::OffsetArray{T,3}, r1::Union(Range1{Int},Colon), i2::Int, i3::Int) = |
101 | | - isa(r1, Colon) ? FA.array[:, i2+FA.o2, i3+FA.o3] : FA.array[r1+FA.o1, i2+FA.o2, i3+FA.o3] |
| 56 | +Base.reshape(A::AbstractArray, inds::Indices) = OffsetArray(reshape(A, map(Base.dimlength, inds)), map(indsoffset, inds)) |
102 | 57 |
|
103 | | -setindex!{T<:Number}(FA::OffsetArray{T,1}, x, r1::Union(Range1{Int},Colon)) = let |
104 | | - if isa(r1, Colon) |
105 | | - FA.array[:] = x[:] |
106 | | - else |
107 | | - FA.array[r1+FA.o1] = x[r1+FA.o1] |
108 | | - end |
| 58 | +@inline function Base.getindex{T,N}(A::OffsetArray{T,N}, I::Vararg{Int,N}) |
| 59 | + @boundscheck checkbounds(A, I...) |
| 60 | + @inbounds ret = parent(A)[offset(A.offsets, I)...] |
| 61 | + ret |
109 | 62 | end |
110 | | - |
111 | | -setindex!{T<:Number}(FA::OffsetArray{T,2}, x, r1::Union(Range1{Int},Colon), i2::Int) = let |
112 | | - if isa(r1, Colon) |
113 | | - FA.array[:, i2+FA.o2] = x[:, i2+FA.o2] |
114 | | - else |
115 | | - FA.array[r1+FA.o1, i2+FA.o2] = x[r1+FA.o1, i2+FA.o2] |
116 | | - end |
| 63 | +@inline function Base._getindex(::LinearFast, A::OffsetVector, i::Int) |
| 64 | + @boundscheck checkbounds(A, i) |
| 65 | + @inbounds ret = parent(A)[offset(A.offsets, (i,))[1]] |
| 66 | + ret |
117 | 67 | end |
118 | | - |
119 | | -setindex!{T<:Number}(FA::OffsetArray{T,3}, x, r1::Union(Range1{Int},Colon), i2::Int, i3::Int) = let |
120 | | - if isa(r1, Colon) |
121 | | - FA.array[:, i2+FA.o2, i3+FA.o3] = x[:, i2+FA.o2, i3+FA.o3] |
122 | | - else |
123 | | - FA.array[r1+FA.o1, i2+FA.o2, i3+FA.o3] = x[r1+FA.o1, i2+FA.o2, i3+FA.o3] |
124 | | - end |
| 68 | +@inline function Base._getindex(::LinearFast, A::OffsetArray, i::Int) |
| 69 | + @boundscheck checkbounds(A, i) |
| 70 | + @inbounds ret = parent(A)[i] |
| 71 | + ret |
| 72 | +end |
| 73 | +@inline function Base.setindex!{T,N}(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) |
| 74 | + @boundscheck checkbounds(A, I...) |
| 75 | + @inbounds parent(A)[offset(A.offsets, I)...] = val |
| 76 | + val |
| 77 | +end |
| 78 | +@inline function Base._setindex!(::LinearFast, A::OffsetVector, val, i::Int) |
| 79 | + @boundscheck checkbounds(A, i) |
| 80 | + @inbounds parent(A)[offset(A.offsets, (i,))[1]] = val |
| 81 | + val |
125 | 82 | end |
| 83 | +@inline function Base._setindex!(::LinearFast, A::OffsetArray, val, i::Int) |
| 84 | + @boundscheck checkbounds(A, i) |
| 85 | + @inbounds parent(A)[i] = val |
| 86 | + val |
| 87 | +end |
| 88 | + |
| 89 | +# Computing a shifted index (subtracting the offset) |
| 90 | +offset{N}(offsets::NTuple{N,Int}, inds::NTuple{N,Int}) = _offset((), offsets, inds) |
| 91 | +_offset(out, ::Tuple{}, ::Tuple{}) = out |
| 92 | +@inline _offset(out, offsets, inds) = _offset((out..., inds[1]-offsets[1]), Base.tail(offsets), Base.tail(inds)) |
126 | 93 |
|
| 94 | +indsoffset(r::Range) = first(r) - 1 |
| 95 | +indsoffset(i::Integer) = 0 |
127 | 96 |
|
128 | 97 | end # module |
0 commit comments