10
10
export OffsetArray, OffsetMatrix, OffsetVector
11
11
12
12
include (" axes.jl" )
13
+ include (" utils.jl" )
13
14
14
- # # OffsetArray
15
- struct OffsetArray{T,N,AA<: AbstractArray } <: AbstractArray{T,N}
16
- parent:: AA
17
- offsets:: NTuple{N,Int}
18
- function OffsetArray {T, N, AA} (parent:: AA , offsets:: NTuple{N, Int} ) where {T, N, AA<: AbstractArray }
19
- overflow_check .(axes (parent), offsets)
20
- new {T, N, AA} (parent, offsets)
21
- end
22
- end
23
- OffsetVector{T,AA<: AbstractArray } = OffsetArray{T,1 ,AA}
24
- OffsetMatrix{T,AA<: AbstractArray } = OffsetArray{T,2 ,AA}
25
-
26
- function overflow_check (r, offset:: T ) where T
27
- # This gives some performance boost https://github.com/JuliaLang/julia/issues/33273
28
- throw_upper_overflow_error () = throw (ArgumentError (" Boundary overflow detected: offset $offset should be equal or less than $(typemax (T) - last (r)) " ))
29
- throw_lower_overflow_error () = throw (ArgumentError (" Boundary overflow detected: offset $offset should be equal or greater than $(typemin (T) - first (r)) " ))
30
-
31
- if offset > 0 && last (r) > typemax (T) - offset
32
- throw_upper_overflow_error ()
33
- elseif offset < 0 && first (r) < typemin (T) - offset
34
- throw_lower_overflow_error ()
35
- end
36
- end
37
-
38
- # # OffsetArray constructors
39
-
40
- offset (axparent:: AbstractUnitRange , ax:: AbstractUnitRange ) = first (ax) - first (axparent)
41
- offset (axparent:: AbstractUnitRange , ax:: Integer ) = 1 - first (axparent)
42
-
43
- function OffsetArray (A:: AbstractArray{T,N} , offsets:: NTuple{N,Int} ) where {T,N}
44
- OffsetArray {T,N,typeof(A)} (A, offsets)
45
- end
46
- OffsetArray (A:: AbstractArray{T,0} , offsets:: Tuple{} ) where T =
47
- OffsetArray {T,0,typeof(A)} (A, ())
48
-
49
- OffsetArray (A:: AbstractArray{T,N} , offsets:: Vararg{Int,N} ) where {T,N} =
50
- OffsetArray (A, offsets)
51
- OffsetArray (A:: AbstractArray{T,0} ) where {T} = OffsetArray (A, ())
52
-
15
+ # Techniquely we know the length of CartesianIndices
16
+ const OffsetAxisKnownLength = Union{Integer, UnitRange, Base. OneTo, IdentityUnitRange, IdOffsetRange}
17
+ const OffsetAxis = Union{OffsetAxisKnownLength, CartesianIndices, Colon}
53
18
const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
54
- OffsetArray {T,N} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} =
55
- OffsetArray (Array {T,N} (init, map (indexlength, inds)), map (indexoffset, inds))
56
- OffsetArray {T} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} = OffsetArray {T,N} (init, inds)
57
- OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
58
- OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
59
-
60
- # OffsetVector constructors
61
- OffsetVector (A:: AbstractVector , offset) = OffsetArray (A, offset)
62
- OffsetVector {T} (init:: ArrayInitializer , inds:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds)
63
-
64
- # OffsetMatrix constructors
65
- OffsetMatrix (A:: AbstractMatrix , offset1, offset2) = OffsetArray (A, offset1, offset2)
66
- OffsetMatrix (A:: AbstractMatrix , I:: CartesianIndices{2} ) = OffsetArray (A, I)
67
- OffsetMatrix {T} (init:: ArrayInitializer , inds1:: AbstractUnitRange , inds2:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds1, inds2)
68
19
20
+ # # OffsetArray
69
21
"""
70
22
OffsetArray(A, indices...)
71
23
@@ -116,84 +68,81 @@ ERROR: [...]
116
68
```
117
69
118
70
"""
119
- function OffsetArray (A:: AbstractArray{T,N} , inds:: NTuple{N,AbstractUnitRange} ) where {T,N}
120
- axparent = axes (A)
121
- lA = map (length, axparent)
122
- lI = map (length, inds)
123
- 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" ))
124
- OffsetArray (A, map (offset, axparent, inds))
71
+ struct OffsetArray{T,N,AA<: AbstractArray } <: AbstractArray{T,N}
72
+ parent:: AA
73
+ offsets:: NTuple{N,Int}
74
+ function OffsetArray {T, N, AA} (parent:: AA , offsets:: NTuple{N, Int} ) where {T, N, AA<: AbstractArray }
75
+ overflow_check .(axes (parent), offsets)
76
+ new {T, N, AA} (parent, offsets)
77
+ end
125
78
end
126
- OffsetArray (A :: AbstractArray {T,N} , inds :: Vararg{AbstractUnitRange,N} ) where {T,N} =
127
- OffsetArray (A, inds)
79
+ const OffsetVector {T,AA <: AbstractArray } = OffsetArray {T,1 ,AA}
80
+ const OffsetMatrix{T,AA <: AbstractArray } = OffsetArray{T, 2 ,AA}
128
81
129
- uncolonindices (A :: AbstractArray{<:Any,N} , inds :: NTuple{N,Any} ) where {N} = uncolonindices ( axes (A), inds)
130
- uncolonindices (ax :: Tuple , inds :: Tuple ) = ( first (inds), uncolonindices ( tail (ax), tail (inds)) ... )
131
- uncolonindices (ax :: Tuple , inds :: Tuple{Colon, Vararg{Any}} ) = ( first (ax), uncolonindices ( tail (ax), tail (inds)) ... )
132
- uncolonindices ( :: Tuple{} , :: Tuple{} ) = ( )
82
+ function overflow_check (r, offset :: T ) where T
83
+ # This gives some performance boost https://github.com/JuliaLang/julia/issues/33273
84
+ throw_upper_overflow_error ( ) = throw ( ArgumentError ( " Boundary overflow detected: offset $offset should be equal or less than $( typemax (T) - last (r)) " ) )
85
+ throw_lower_overflow_error () = throw ( ArgumentError ( " Boundary overflow detected: offset $offset should be equal or greater than $( typemin (T) - first (r)) " ) )
133
86
134
- function OffsetArray (A:: AbstractArray{T,N} , inds:: NTuple{N,Union{AbstractUnitRange, CartesianIndices{1}, Colon}} ) where {T,N}
135
- OffsetArray (A, uncolonindices (A, inds))
136
- end
137
- OffsetArray (A:: AbstractArray{T,N} , inds:: Vararg{Union{AbstractUnitRange, CartesianIndices{1}, Colon},N} ) where {T,N} =
138
- OffsetArray (A, uncolonindices (A, inds))
139
-
140
- # Specify offsets using CartesianIndices (issue #71)
141
- # Support a mix of AbstractUnitRanges and CartesianIndices{1}
142
- # Extract the range r from CartesianIndices((r,))
143
- function stripCartesianIndices (inds:: Tuple{CartesianIndices{1},Vararg{Any}} )
144
- I = first (inds)
145
- Ir = convert (Tuple{AbstractUnitRange{Int}}, I) |> first
146
- (Ir, stripCartesianIndices (tail (inds))... )
147
- end
148
- stripCartesianIndices (inds:: Tuple )= (first (inds), stripCartesianIndices (tail (inds))... )
149
- stripCartesianIndices (:: Tuple{} ) = ()
150
-
151
- OffsetArray (A:: AbstractArray{<:Any,N} , inds:: NTuple{N,Union{CartesianIndices{1}, AbstractUnitRange}} ) where {N} =
152
- OffsetArray (A, stripCartesianIndices (inds))
153
- OffsetArray (A:: AbstractArray{<:Any,N} , inds:: Vararg{Union{CartesianIndices{1}, AbstractUnitRange},N} ) where {N} =
154
- OffsetArray (A, inds)
155
-
156
- # Support an arbitrary CartesianIndices alongside colons and ranges
157
- # The total number of indices should equal ndims(arr)
158
- # We split the CartesianIndices{N} into N CartesianIndices{1} indices to facilitate dispatch
159
- splitCartesianIndices (c:: CartesianIndices{0} ) = ()
160
- function splitCartesianIndices (c:: CartesianIndices )
161
- c1, ct = Base. IteratorsMD. split (c, Val (1 ))
162
- (c1, splitCartesianIndices (ct)... )
163
- end
164
- function splitCartesianIndices (t:: Tuple{CartesianIndices, Vararg{Any}} )
165
- (splitCartesianIndices (first (t))... , splitCartesianIndices (tail (t))... )
166
- end
167
- function splitCartesianIndices (t:: Tuple )
168
- (first (t), splitCartesianIndices (tail (t))... )
87
+ if offset > 0 && last (r) > typemax (T) - offset
88
+ throw_upper_overflow_error ()
89
+ elseif offset < 0 && first (r) < typemin (T) - offset
90
+ throw_lower_overflow_error ()
91
+ end
169
92
end
170
- splitCartesianIndices ( :: Tuple{} ) = ()
93
+ # # OffsetArray constructors
171
94
172
- function OffsetArray (A:: AbstractArray , inds:: Tuple{Vararg{Union{AbstractUnitRange, CartesianIndices, Colon}}} )
173
- OffsetArray (A, splitCartesianIndices (inds))
174
- end
175
- function OffsetArray (A:: AbstractArray , inds:: Vararg{Union{AbstractUnitRange, CartesianIndices, Colon}} )
176
- OffsetArray (A, inds)
95
+ for FT in (:OffsetArray , :OffsetVector , :OffsetMatrix )
96
+ # The only route out to inner constructor
97
+ @eval function $FT (A:: AbstractArray{T} , offsets:: NTuple{N, Integer} ) where {T, N}
98
+ ndims (A) == N || throw (DimensionMismatch (" Array dimensions should equal to number of offsets" ))
99
+ OffsetArray {T, ndims(A), typeof(A)} (A, offsets)
100
+ end
101
+ # nested OffsetArrays
102
+ @eval function $FT (A:: OffsetArray{T} , offsets:: NTuple{N, Integer} ) where {T,N}
103
+ $ FT (parent (A), A. offsets .+ offsets)
104
+ end
105
+ # convert ranges to offsets
106
+ @eval function $FT (A:: AbstractArray{T} , inds:: NTuple{N,OffsetAxisKnownLength} ) where {T,N}
107
+ axparent = axes (A)
108
+ lA = map (length, axparent)
109
+ lI = map (length, inds)
110
+ 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" ))
111
+ $ FT (A, map (_offset, axparent, inds))
112
+ end
113
+ # lower CartesianIndices and Colon
114
+ @eval function $FT (A:: AbstractArray{T} , inds:: NTuple{N, OffsetAxis} ) where {T, N}
115
+ indsN = _uncolonindices (A, _stripCartesianIndices (_splitCartesianIndices (inds)))
116
+ $ FT (A, indsN)
117
+ end
118
+ @eval function $FT (A:: AbstractArray{T} , inds:: Vararg{OffsetAxis,N} ) where {T, N}
119
+ $ FT (A, _uncolonindices (A, _stripCartesianIndices (_splitCartesianIndices (inds))))
120
+ end
121
+ @eval $ FT (A:: AbstractArray , inds:: CartesianIndices ) = $ FT (A, inds. indices)
177
122
end
178
123
179
- # Add methods to initialize OffsetArrays using CartesianIndices (issue #71)
180
- function OffsetArray {T,N} (init:: ArrayInitializer , inds:: Tuple{Vararg{Union{AbstractUnitRange, CartesianIndices}}} ) where {T,N}
181
- indsN = stripCartesianIndices (splitCartesianIndices (inds))
182
- OffsetArray {T,N} (init, indsN)
124
+ # array initialization
125
+ OffsetArray {T,N} (init:: ArrayInitializer , inds:: NTuple{N, OffsetAxisKnownLength} ) where {T,N} =
126
+ OffsetArray (Array {T,N} (init, map (_indexlength, inds)), map (_indexoffset, inds))
127
+ OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{OffsetAxisKnownLength,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
128
+ function OffsetArray {T, N} (init:: ArrayInitializer , inds:: NTuple{N, Union{OffsetAxisKnownLength, CartesianIndices}} ) where {T, N}
129
+ OffsetArray {T, N} (init, _stripCartesianIndices (_splitCartesianIndices (inds)))
183
130
end
184
- function OffsetArray {T} (init:: ArrayInitializer , inds:: Tuple{Vararg{Union{AbstractUnitRange, CartesianIndices}}} ) where {T}
185
- indsN = stripCartesianIndices (splitCartesianIndices (inds))
186
- OffsetArray {T} (init, indsN)
131
+ function OffsetArray {T, N} (init:: ArrayInitializer , inds:: Vararg{Union{OffsetAxisKnownLength, CartesianIndices}} ) where {T, N}
132
+ OffsetArray {T, N} (init, inds)
187
133
end
188
- OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{Union{AbstractUnitRange, CartesianIndices}} ) where {T,N} = OffsetArray {T,N} (init, inds)
189
- OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{Union{AbstractUnitRange, CartesianIndices}} ) where {T} = OffsetArray {T} (init, inds)
134
+ OffsetArray {T, N} (init:: ArrayInitializer , inds:: CartesianIndices{N} ) where {T,N} = OffsetArray {T, N} (init, inds. indices)
190
135
191
- # avoid a level of indirection when nesting OffsetArrays
192
- function OffsetArray (A:: OffsetArray , offsets:: NTuple{N,Int} ) where {N}
193
- OffsetArray (parent (A), offsets .+ A. offsets)
136
+ OffsetArray {T} (init:: ArrayInitializer , inds:: NTuple{N, OffsetAxisKnownLength} ) where {T,N} = OffsetArray {T,N} (init, inds)
137
+ OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{OffsetAxisKnownLength,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
138
+ function OffsetArray {T} (init:: ArrayInitializer , inds:: NTuple{N, Union{OffsetAxisKnownLength, CartesianIndices}} ) where {T, N}
139
+ indsN = _stripCartesianIndices (_splitCartesianIndices (inds)) # CartesianIndices might contain multiple dimensions
140
+ OffsetArray {T, length(indsN)} (init, _stripCartesianIndices (_splitCartesianIndices (inds)))
141
+ end
142
+ function OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{Union{OffsetAxisKnownLength, CartesianIndices}, N} ) where {T, N}
143
+ OffsetArray {T} (init, inds)
194
144
end
195
- OffsetArray (A:: OffsetArray{T,0} , inds:: Tuple{} ) where {T} = OffsetArray (parent (A), ())
196
- # OffsetArray(A::OffsetArray{T,N}, inds::Tuple{}) where {T,N} = error("this should never be called")
145
+ OffsetArray {T} (init:: ArrayInitializer , inds:: CartesianIndices{N} ) where {T,N} = OffsetArray {T, N} (init, inds. indices)
197
146
198
147
Base. IndexStyle (:: Type{OA} ) where {OA<: OffsetArray } = IndexStyle (parenttype (OA))
199
148
parenttype (:: Type{OffsetArray{T,N,AA}} ) where {T,N,AA} = AA
@@ -211,27 +160,24 @@ Base.eachindex(::IndexLinear, A::OffsetVector) = axes(A, 1)
211
160
@inline Base. axes (A:: OffsetArray , d) = d <= ndims (A) ? IdOffsetRange (axes (parent (A), d), A. offsets[d]) : IdOffsetRange (axes (parent (A), d))
212
161
@inline Base. axes1 (A:: OffsetArray{T,0} ) where {T} = IdOffsetRange (axes (parent (A), 1 )) # we only need to specialize this one
213
162
214
- const OffsetAxisKnownLength = Union{Integer, UnitRange, Base. OneTo, IdentityUnitRange, IdOffsetRange}
215
-
216
163
Base. similar (A:: OffsetArray , :: Type{T} , dims:: Dims ) where T =
217
164
similar (parent (A), T, dims)
218
165
function Base. similar (A:: AbstractArray , :: Type{T} , inds:: Tuple{OffsetAxisKnownLength,Vararg{OffsetAxisKnownLength}} ) where T
219
- B = similar (A, T, map (indexlength , inds))
220
- return OffsetArray (B, map (offset , axes (B), inds))
166
+ B = similar (A, T, map (_indexlength , inds))
167
+ return OffsetArray (B, map (_offset , axes (B), inds))
221
168
end
222
169
223
170
# reshape accepts a single colon
224
- const OffsetAxis = Union{OffsetAxisKnownLength, Colon}
225
171
Base. reshape (A:: AbstractArray , inds:: OffsetAxis... ) = reshape (A, inds)
226
172
function Base. reshape (A:: AbstractArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} )
227
- AR = reshape (A, map (indexlength , inds))
228
- return OffsetArray (AR, map (offset , axes (AR), inds))
173
+ AR = reshape (A, map (_indexlength , inds))
174
+ return OffsetArray (AR, map (_offset , axes (AR), inds))
229
175
end
230
176
231
177
# Reshaping OffsetArrays can "pop" the original OffsetArray wrapper and return
232
178
# an OffsetArray(reshape(...)) instead of an OffsetArray(reshape(OffsetArray(...)))
233
179
Base. reshape (A:: OffsetArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) =
234
- OffsetArray (reshape (parent (A), map (indexlength , inds)), map (indexoffset , inds))
180
+ OffsetArray (reshape (parent (A), map (_indexlength , inds)), map (_indexoffset , inds))
235
181
# And for non-offset axes, we can just return a reshape of the parent directly
236
182
Base. reshape (A:: OffsetArray , inds:: Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}} ) = reshape (parent (A), inds)
237
183
Base. reshape (A:: OffsetArray , inds:: Dims ) = reshape (parent (A), inds)
@@ -241,8 +187,8 @@ Base.reshape(A::OffsetArray, inds::Union{Int,Colon}...) = reshape(parent(A), ind
241
187
Base. reshape (A:: OffsetArray , inds:: Tuple{Vararg{Union{Int,Colon}}} ) = reshape (parent (A), inds)
242
188
243
189
function Base. similar (:: Type{T} , shape:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where {T<: AbstractArray }
244
- P = T (undef, map (indexlength , shape))
245
- OffsetArray (P, map (offset , axes (P), shape))
190
+ P = T (undef, map (_indexlength , shape))
191
+ OffsetArray (P, map (_offset , axes (P), shape))
246
192
end
247
193
248
194
Base. fill (v, inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
@@ -339,15 +285,6 @@ Base.pop!(A::OffsetVector) = pop!(A.parent)
339
285
Base. append! (A:: OffsetVector , items) = (append! (A. parent, items); A)
340
286
Base. empty! (A:: OffsetVector ) = (empty! (A. parent); A)
341
287
342
- # ## Low-level utilities ###
343
-
344
- indexoffset (r:: AbstractRange ) = first (r) - 1
345
- indexoffset (i:: Integer ) = 0
346
- indexoffset (i:: Colon ) = 0
347
- indexlength (r:: AbstractRange ) = length (r)
348
- indexlength (i:: Integer ) = i
349
- indexlength (i:: Colon ) = Colon ()
350
-
351
288
# These functions keep the summary compact
352
289
function Base. inds2string (inds:: Tuple {Vararg{Union{IdOffsetRange, IdentityUnitRange{<: IdOffsetRange }}}})
353
290
Base. inds2string (map (UnitRange, inds))
0 commit comments