1
- VERSION < v " 0.7.0-beta2.199" && __precompile__ ()
2
-
3
1
module OffsetArrays
4
2
5
3
using Base: Indices, tail, @propagate_inbounds
11
9
12
10
export OffsetArray, OffsetVector
13
11
12
+ """
13
+ ro = IdOffsetRange(r::AbstractUnitRange, offset)
14
+
15
+ Construct an "identity offset range". Numerically, `collect(ro) == collect(r) .+ offset`,
16
+ with the additional property that `axes(ro) = (ro,)`, which is where the "identity" comes from.
17
+ """
18
+ struct IdOffsetRange{T<: Integer ,I<: AbstractUnitRange{T} } <: AbstractUnitRange{T}
19
+ parent:: I
20
+ offset:: T
21
+ end
22
+ IdOffsetRange (r:: AbstractUnitRange{T} , offset:: Integer ) where T =
23
+ IdOffsetRange {T,typeof(r)} (r, convert (T, offset))
24
+
25
+ @inline Base. axes (r:: IdOffsetRange ) = (Base. axes1 (r),)
26
+ @inline Base. axes1 (r:: IdOffsetRange ) = IdOffsetRange (Base. axes1 (r. parent), r. offset)
27
+ @inline Base. unsafe_indices (r:: IdOffsetRange ) = (r,)
28
+ @inline Base. length (r:: IdOffsetRange ) = length (r. parent)
29
+
30
+ function Base. iterate (r:: IdOffsetRange )
31
+ ret = iterate (r. parent)
32
+ ret === nothing && return nothing
33
+ return (ret[1 ] + r. offset, ret[2 ])
34
+ end
35
+ function Base. iterate (r:: IdOffsetRange , i) where T
36
+ ret = iterate (r. parent, i)
37
+ ret === nothing && return nothing
38
+ return (ret[1 ] + r. offset, ret[2 ])
39
+ end
40
+
41
+ @inline Base. first (r:: IdOffsetRange ) = first (r. parent) + r. offset
42
+ @inline Base. last (r:: IdOffsetRange ) = last (r. parent) + r. offset
43
+
44
+ @propagate_inbounds Base. getindex (r:: IdOffsetRange , i:: Integer ) = r. parent[i - r. offset] + r. offset
45
+ @propagate_inbounds function Base. getindex (r:: IdOffsetRange , s:: AbstractUnitRange{<:Integer} )
46
+ return r. parent[s .- r. offset] .+ r. offset
47
+ end
48
+
49
+ Base. show (io:: IO , r:: IdOffsetRange ) = print (io, first (r), ' :' , last (r))
50
+
51
+ # Optimizations
52
+ @inline Base. checkindex (:: Type{Bool} , inds:: IdOffsetRange , i:: Real ) = Base. checkindex (Bool, inds. parent, i - inds. offset)
53
+
54
+ # # OffsetArray
14
55
struct OffsetArray{T,N,AA<: AbstractArray } <: AbstractArray{T,N}
15
56
parent:: AA
16
57
offsets:: NTuple{N,Int}
17
58
end
18
59
OffsetVector{T,AA<: AbstractArray } = OffsetArray{T,1 ,AA}
19
60
20
- OffsetArray (A:: AbstractArray{T,N} , offsets:: NTuple{N,Int} ) where {T,N} =
61
+ # # OffsetArray constructors
62
+
63
+ offset (axparent:: AbstractUnitRange , ax:: AbstractUnitRange ) = first (ax) - first (axparent)
64
+ offset (axparent:: AbstractUnitRange , ax:: Integer ) = 1 - first (axparent)
65
+
66
+ function OffsetArray (A:: AbstractArray{T,N} , offsets:: NTuple{N,Int} ) where {T,N}
21
67
OffsetArray {T,N,typeof(A)} (A, offsets)
68
+ end
69
+ OffsetArray (A:: AbstractArray{T,0} , offsets:: Tuple{} ) where T =
70
+ OffsetArray {T,0,typeof(A)} (A, ())
71
+
22
72
OffsetArray (A:: AbstractArray{T,N} , offsets:: Vararg{Int,N} ) where {T,N} =
23
73
OffsetArray (A, offsets)
74
+ OffsetArray (A:: AbstractArray{T,0} ) where {T} = OffsetArray (A, ())
24
75
25
76
const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
26
77
OffsetArray {T,N} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} =
27
- OffsetArray {T,N,Array{T,N}} (Array {T,N} (init, map (indexlength, inds)), map (indexoffset, inds))
78
+ OffsetArray (Array {T,N} (init, map (indexlength, inds)), map (indexoffset, inds))
28
79
OffsetArray {T} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} = OffsetArray {T,N} (init, inds)
29
80
OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
30
81
OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
31
- OffsetArray (A:: AbstractArray{T,0} ) where {T} = OffsetArray {T,0,typeof(A)} (A, ())
32
82
33
83
# OffsetVector constructors
34
84
OffsetVector (A:: AbstractVector , offset) = OffsetArray (A, offset)
35
85
OffsetVector {T} (init:: ArrayInitializer , inds:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds)
36
86
37
- # deprecated constructors
38
- using Base: @deprecate
39
-
40
- @deprecate OffsetArray (:: Type{T} , inds:: Vararg{UnitRange{Int},N} ) where {T,N} OffsetArray {T} (undef, inds)
41
- @deprecate OffsetVector (:: Type{T} , inds:: AbstractUnitRange ) where {T} OffsetVector {T} (undef, inds)
42
- @deprecate OffsetArray {T,N} (inds:: Indices{N} ) where {T,N} OffsetArray {T,N} (undef, inds)
43
- @deprecate OffsetArray {T} (inds:: Indices{N} ) where {T,N} OffsetArray {T} (undef, inds)
44
- @deprecate OffsetArray {T,N} (inds:: Vararg{AbstractUnitRange,N} ) where {T,N} OffsetArray {T,N} (undef, inds)
45
- @deprecate OffsetArray {T} (inds:: Vararg{AbstractUnitRange,N} ) where {T,N} OffsetArray {T} (undef, inds)
46
- @deprecate OffsetVector {T} (inds:: AbstractUnitRange ) where {T} OffsetVector {T} (undef, inds)
47
-
48
- # The next two are necessary for ambiguity resolution. Really, the
49
- # second method should not be necessary.
50
- OffsetArray (A:: AbstractArray{T,0} , inds:: Tuple{} ) where {T} = OffsetArray {T,0,typeof(A)} (A, ())
51
- OffsetArray (A:: AbstractArray{T,N} , inds:: Tuple{} ) where {T,N} = error (" this should never be called" )
87
+ # # The next two are necessary for ambiguity resolution. Really, the
88
+ # # second method should not be necessary.
89
+ # OffsetArray(A::AbstractArray{T,0}, inds::Tuple{}) where {T} = OffsetArray{T,0,typeof(A)}(A, ())
90
+ # OffsetArray(A::AbstractArray{T,N}, inds::Tuple{}) where {T,N} = error("this should never be called")
91
+
52
92
function OffsetArray (A:: AbstractArray{T,N} , inds:: NTuple{N,AbstractUnitRange} ) where {T,N}
53
- lA = map (indexlength, axes (A))
54
- lI = map (indexlength, inds)
93
+ axparent = axes (A)
94
+ lA = map (length, axparent)
95
+ lI = map (length, inds)
55
96
lA == lI || throw (DimensionMismatch (" supplied axes do not agree with the size of the array (got size $lA for the array and $lI for the indices" ))
56
- OffsetArray (A, map (indexoffset , inds))
97
+ OffsetArray (A, map (offset, axparent , inds))
57
98
end
58
99
OffsetArray (A:: AbstractArray{T,N} , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} =
59
100
OffsetArray (A, inds)
@@ -62,8 +103,8 @@ OffsetArray(A::AbstractArray{T,N}, inds::Vararg{AbstractUnitRange,N}) where {T,N
62
103
function OffsetArray (A:: OffsetArray , inds:: NTuple{N,AbstractUnitRange} ) where {N}
63
104
OffsetArray (parent (A), inds)
64
105
end
65
- OffsetArray (A:: OffsetArray{T,0} , inds:: Tuple{} ) where {T} = OffsetArray {T,0,typeof(A)} (parent (A), ())
66
- OffsetArray (A:: OffsetArray{T,N} , inds:: Tuple{} ) where {T,N} = error (" this should never be called" )
106
+ OffsetArray (A:: OffsetArray{T,0} , inds:: Tuple{} ) where {T} = OffsetArray (parent (A), ())
107
+ # OffsetArray(A::OffsetArray{T,N}, inds::Tuple{}) where {T,N} = error("this should never be called")
67
108
68
109
Base. IndexStyle (:: Type{OA} ) where {OA<: OffsetArray } = IndexStyle (parenttype (OA))
69
110
parenttype (:: Type{OffsetArray{T,N,AA}} ) where {T,N,AA} = AA
@@ -74,36 +115,26 @@ Base.parent(A::OffsetArray) = A.parent
74
115
Base. eachindex (:: IndexCartesian , A:: OffsetArray ) = CartesianIndices (axes (A))
75
116
Base. eachindex (:: IndexLinear , A:: OffsetVector ) = axes (A, 1 )
76
117
77
- Base. size (A:: OffsetArray ) = size (parent (A))
78
- Base. size (A:: OffsetArray , d) = size (parent (A), d)
79
-
80
- # Implementations of axes and indices1. Since bounds-checking is
81
- # performance-critical and relies on axes, these are usually worth
82
- # optimizing thoroughly.
83
- @inline Base. axes (A:: OffsetArray , d) =
84
- 1 <= d <= length (A. offsets) ? _slice (axes (parent (A))[d], A. offsets[d]) : (1 : 1 )
85
- @inline Base. axes (A:: OffsetArray ) =
86
- _axes (axes (parent (A)), A. offsets) # would rather use ntuple, but see #15276
87
- @inline _axes (inds, offsets) =
88
- (_slice (inds[1 ], offsets[1 ]), _axes (tail (inds), tail (offsets))... )
89
- _axes (:: Tuple{} , :: Tuple{} ) = ()
90
- Base. axes1 (A:: OffsetArray{T,0} ) where {T} = 1 : 1 # we only need to specialize this one
91
-
92
- # Avoid the kw-arg on the range(r+x, length=length(r)) call in r .+ x
93
- @inline _slice (r, x) = IdentityUnitRange (Base. _range (first (r) + x, nothing , nothing , length (r)))
94
-
95
- const OffsetAxis = Union{Integer, UnitRange, Base. OneTo, IdentityUnitRange, Colon}
96
- function Base. similar (A:: OffsetArray , :: Type{T} , dims:: Dims ) where T
97
- B = similar (parent (A), T, dims)
98
- end
118
+ @inline Base. size (A:: OffsetArray ) = size (parent (A))
119
+ @inline Base. size (A:: OffsetArray , d) = size (parent (A), d)
120
+
121
+ @inline Base. axes (A:: OffsetArray ) = map (IdOffsetRange, axes (parent (A)), A. offsets)
122
+ @inline Base. axes (A:: OffsetArray , d) = d <= ndims (A) ? IdOffsetRange (axes (parent (A), d), A. offsets[d]) : Base. OneTo (1 )
123
+ @inline Base. axes1 (A:: OffsetArray{T,0} ) where {T} = Base. OneTo (1 ) # we only need to specialize this one
124
+
125
+ const OffsetAxis = Union{Integer, UnitRange, Base. OneTo, IdentityUnitRange, IdOffsetRange, Colon}
126
+ Base. similar (A:: OffsetArray , :: Type{T} , dims:: Dims ) where T =
127
+ similar (parent (A), T, dims)
99
128
function Base. similar (A:: AbstractArray , :: Type{T} , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where T
100
129
B = similar (A, T, map (indexlength, inds))
101
- OffsetArray (B, map (indexoffset , inds))
130
+ return OffsetArray (B, map (offset, axes (B) , inds))
102
131
end
103
132
104
133
Base. reshape (A:: AbstractArray , inds:: OffsetAxis... ) = reshape (A, inds)
105
- Base. reshape (A:: AbstractArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) =
106
- OffsetArray (reshape (A, map (indexlength, inds)), map (indexoffset, inds))
134
+ function Base. reshape (A:: AbstractArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} )
135
+ AR = reshape (A, map (indexlength, inds))
136
+ return OffsetArray (AR, map (offset, axes (AR), inds))
137
+ end
107
138
108
139
# Reshaping OffsetArrays can "pop" the original OffsetArray wrapper and return
109
140
# an OffsetArray(reshape(...)) instead of an OffsetArray(reshape(OffsetArray(...)))
@@ -116,8 +147,10 @@ Base.reshape(A::OffsetArray, ::Colon) = A
116
147
Base. reshape (A:: OffsetArray , inds:: Union{Int,Colon} ...) = reshape (parent (A), inds)
117
148
Base. reshape (A:: OffsetArray , inds:: Tuple{Vararg{Union{Int,Colon}}} ) = reshape (parent (A), inds)
118
149
119
- Base. similar (:: Type{T} , shape:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where {T<: AbstractArray } =
120
- OffsetArray (T (undef, map (indexlength, shape)), map (indexoffset, shape))
150
+ function Base. similar (:: Type{T} , shape:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where {T<: AbstractArray }
151
+ P = T (undef, map (indexlength, shape))
152
+ OffsetArray (P, map (offset, axes (P), shape))
153
+ end
121
154
122
155
Base. fill (v, inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
123
156
fill! (OffsetArray (Array {typeof(v), N} (undef, map (indexlength, inds)), map (indexoffset, inds)), v)
@@ -130,39 +163,44 @@ Base.trues(inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} =
130
163
Base. falses (inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
131
164
fill! (OffsetArray (BitArray {N} (undef, map (indexlength, inds)), map (indexoffset, inds)), false )
132
165
133
- @inline @propagate_inbounds function Base. getindex (A:: OffsetArray{T,N} , I:: Vararg{Int,N} ) where {T,N}
134
- @boundscheck checkbounds (A, I... )
135
- @inbounds ret = parent (A)[offset (A. offsets, I)... ]
136
- ret
137
- end
138
- @inline @propagate_inbounds function Base. getindex (A:: OffsetVector , i:: Int )
139
- @boundscheck checkbounds (A, i)
140
- @inbounds ret = parent (A)[offset (A. offsets, (i,))[1 ]]
141
- ret
142
- end
143
- @inline @propagate_inbounds function Base. getindex (A:: OffsetArray , i:: Int )
144
- @boundscheck checkbounds (A, i)
145
- @inbounds ret = parent (A)[i]
146
- ret
166
+ # # Indexing
167
+
168
+ # Note this gets the index of the parent *array*, not the index of the parent *range*
169
+ # Here's how one can think about this:
170
+ # Δi = i - first(r)
171
+ # i′ = first(r.parent) + Δi
172
+ # and one obtains the result below.
173
+ parentindex (r:: IdOffsetRange , i) = i - r. offset
174
+
175
+ @propagate_inbounds function Base. getindex (A:: OffsetArray{T,N} , I:: Vararg{Int,N} ) where {T,N}
176
+ J = map (parentindex, axes (A), I)
177
+ return parent (A)[J... ]
147
178
end
148
- @inline @propagate_inbounds function Base. setindex! (A:: OffsetArray{T,N} , val, I:: Vararg{Int,N} ) where {T,N}
179
+
180
+ @propagate_inbounds Base. getindex (A:: OffsetVector , i:: Int ) = parent (A)[parentindex (Base. axes1 (A), i)]
181
+ @propagate_inbounds Base. getindex (A:: OffsetArray , i:: Int ) = parent (A)[i]
182
+
183
+ @propagate_inbounds function Base. setindex! (A:: OffsetArray{T,N} , val, I:: Vararg{Int,N} ) where {T,N}
149
184
@boundscheck checkbounds (A, I... )
150
- @inbounds parent (A)[offset (A. offsets, I)... ] = val
185
+ J = @inbounds map (parentindex, axes (A), I)
186
+ @inbounds parent (A)[J... ] = val
151
187
val
152
188
end
153
- @inline @propagate_inbounds function Base. setindex! (A:: OffsetVector , val, i:: Int )
189
+
190
+ @propagate_inbounds function Base. setindex! (A:: OffsetVector , val, i:: Int )
154
191
@boundscheck checkbounds (A, i)
155
- @inbounds parent (A)[offset (A . offsets, (i,))[ 1 ] ] = val
192
+ @inbounds parent (A)[parentindex (Base . axes1 (A), i) ] = val
156
193
val
157
194
end
158
- @inline @ propagate_inbounds function Base. setindex! (A:: OffsetArray , val, i:: Int )
195
+ @propagate_inbounds function Base. setindex! (A:: OffsetArray , val, i:: Int )
159
196
@boundscheck checkbounds (A, i)
160
197
@inbounds parent (A)[i] = val
161
198
val
162
199
end
163
200
164
201
# For fast broadcasting: ref https://discourse.julialang.org/t/why-is-there-a-performance-hit-on-broadcasting-with-offsetarrays/32194
165
202
Base. dataids (A:: OffsetArray ) = Base. dataids (parent (A))
203
+ Broadcast. broadcast_unalias (dest:: OffsetArray , src:: OffsetArray ) = parent (dest) === parent (src) ? src : Broadcast. unalias (dest, src)
166
204
167
205
# ## Special handling for AbstractRange
168
206
@@ -175,10 +213,10 @@ Base.getindex(a::OffsetRange, r::OffsetRange) = OffsetArray(a[parent(r)], r.offs
175
213
Base. getindex (a:: OffsetRange , r:: AbstractRange ) = a. parent[r .- a. offsets[1 ]]
176
214
Base. getindex (a:: AbstractRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
177
215
178
- @inline @ propagate_inbounds Base. getindex (r:: UnitRange , s:: IIUR ) =
216
+ @propagate_inbounds Base. getindex (r:: UnitRange , s:: IIUR ) =
179
217
OffsetArray (r[s. indices], s)
180
218
181
- @inline @ propagate_inbounds Base. getindex (r:: StepRange , s:: IIUR ) =
219
+ @propagate_inbounds Base. getindex (r:: StepRange , s:: IIUR ) =
182
220
OffsetArray (r[s. indices], s)
183
221
184
222
@inline @propagate_inbounds Base. getindex (r:: StepRangeLen{T,<:Base.TwicePrecision,<:Base.TwicePrecision} , s:: IIUR ) where T =
@@ -212,25 +250,13 @@ Base.empty!(A::OffsetVector) = (empty!(A.parent); A)
212
250
213
251
# ## Low-level utilities ###
214
252
215
- # Computing a shifted index (subtracting the offset)
216
- @inline offset (offsets:: NTuple{N,Int} , inds:: NTuple{N,Int} ) where {N} =
217
- (inds[1 ]- offsets[1 ], offset (Base. tail (offsets), Base. tail (inds))... )
218
- offset (:: Tuple{} , :: Tuple{} ) = ()
219
-
220
- # Support trailing 1s
221
- @inline offset (offsets:: Tuple{Vararg{Int}} , inds:: Tuple{Vararg{Int}} ) =
222
- (offset (offsets, Base. front (inds))... , inds[end ])
223
- offset (offsets:: Tuple{Vararg{Int}} , inds:: Tuple{} ) = error (" inds cannot be shorter than offsets" )
224
-
225
253
indexoffset (r:: AbstractRange ) = first (r) - 1
226
254
indexoffset (i:: Integer ) = 0
227
255
indexoffset (i:: Colon ) = 0
228
256
indexlength (r:: AbstractRange ) = length (r)
229
257
indexlength (i:: Integer ) = i
230
258
indexlength (i:: Colon ) = Colon ()
231
259
232
- @eval @deprecate $ (Symbol (" @unsafe" )) $ (Symbol (" @inbounds" ))
233
-
234
260
function Base. showarg (io:: IO , a:: OffsetArray , toplevel)
235
261
print (io, " OffsetArray(" )
236
262
Base. showarg (io, parent (a), false )
0 commit comments