1- VERSION < v " 0.7.0-beta2.199" && __precompile__ ()
2-
31module OffsetArrays
42
53using Base: Indices, tail, @propagate_inbounds
119
1210export OffsetArray, OffsetVector
1311
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
1455struct OffsetArray{T,N,AA<: AbstractArray } <: AbstractArray{T,N}
1556 parent:: AA
1657 offsets:: NTuple{N,Int}
1758end
1859OffsetVector{T,AA<: AbstractArray } = OffsetArray{T,1 ,AA}
1960
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}
2167 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+
2272OffsetArray (A:: AbstractArray{T,N} , offsets:: Vararg{Int,N} ) where {T,N} =
2373 OffsetArray (A, offsets)
74+ OffsetArray (A:: AbstractArray{T,0} ) where {T} = OffsetArray (A, ())
2475
2576const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
2677OffsetArray {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))
2879OffsetArray {T} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} = OffsetArray {T,N} (init, inds)
2980OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
3081OffsetArray {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, ())
3282
3383# OffsetVector constructors
3484OffsetVector (A:: AbstractVector , offset) = OffsetArray (A, offset)
3585OffsetVector {T} (init:: ArrayInitializer , inds:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds)
3686
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+
5292function 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)
5596 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))
5798end
5899OffsetArray (A:: AbstractArray{T,N} , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} =
59100 OffsetArray (A, inds)
@@ -62,8 +103,8 @@ OffsetArray(A::AbstractArray{T,N}, inds::Vararg{AbstractUnitRange,N}) where {T,N
62103function OffsetArray (A:: OffsetArray , inds:: NTuple{N,AbstractUnitRange} ) where {N}
63104 OffsetArray (parent (A), inds)
64105end
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")
67108
68109Base. IndexStyle (:: Type{OA} ) where {OA<: OffsetArray } = IndexStyle (parenttype (OA))
69110parenttype (:: Type{OffsetArray{T,N,AA}} ) where {T,N,AA} = AA
@@ -74,36 +115,26 @@ Base.parent(A::OffsetArray) = A.parent
74115Base. eachindex (:: IndexCartesian , A:: OffsetArray ) = CartesianIndices (axes (A))
75116Base. eachindex (:: IndexLinear , A:: OffsetVector ) = axes (A, 1 )
76117
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)
99128function Base. similar (A:: AbstractArray , :: Type{T} , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where T
100129 B = similar (A, T, map (indexlength, inds))
101- OffsetArray (B, map (indexoffset , inds))
130+ return OffsetArray (B, map (offset, axes (B) , inds))
102131end
103132
104133Base. 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
107138
108139# Reshaping OffsetArrays can "pop" the original OffsetArray wrapper and return
109140# an OffsetArray(reshape(...)) instead of an OffsetArray(reshape(OffsetArray(...)))
@@ -116,8 +147,10 @@ Base.reshape(A::OffsetArray, ::Colon) = A
116147Base. reshape (A:: OffsetArray , inds:: Union{Int,Colon} ...) = reshape (parent (A), inds)
117148Base. reshape (A:: OffsetArray , inds:: Tuple{Vararg{Union{Int,Colon}}} ) = reshape (parent (A), inds)
118149
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
121154
122155Base. fill (v, inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
123156 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} =
130163Base. falses (inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
131164 fill! (OffsetArray (BitArray {N} (undef, map (indexlength, inds)), map (indexoffset, inds)), false )
132165
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... ]
147178end
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}
149184 @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
151187 val
152188end
153- @inline @propagate_inbounds function Base. setindex! (A:: OffsetVector , val, i:: Int )
189+
190+ @propagate_inbounds function Base. setindex! (A:: OffsetVector , val, i:: Int )
154191 @boundscheck checkbounds (A, i)
155- @inbounds parent (A)[offset (A . offsets, (i,))[ 1 ] ] = val
192+ @inbounds parent (A)[parentindex (Base . axes1 (A), i) ] = val
156193 val
157194end
158- @inline @ propagate_inbounds function Base. setindex! (A:: OffsetArray , val, i:: Int )
195+ @propagate_inbounds function Base. setindex! (A:: OffsetArray , val, i:: Int )
159196 @boundscheck checkbounds (A, i)
160197 @inbounds parent (A)[i] = val
161198 val
162199end
163200
164201# For fast broadcasting: ref https://discourse.julialang.org/t/why-is-there-a-performance-hit-on-broadcasting-with-offsetarrays/32194
165202Base. dataids (A:: OffsetArray ) = Base. dataids (parent (A))
203+ Broadcast. broadcast_unalias (dest:: OffsetArray , src:: OffsetArray ) = parent (dest) === parent (src) ? src : Broadcast. unalias (dest, src)
166204
167205# ## Special handling for AbstractRange
168206
@@ -175,10 +213,10 @@ Base.getindex(a::OffsetRange, r::OffsetRange) = OffsetArray(a[parent(r)], r.offs
175213Base. getindex (a:: OffsetRange , r:: AbstractRange ) = a. parent[r .- a. offsets[1 ]]
176214Base. getindex (a:: AbstractRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
177215
178- @inline @ propagate_inbounds Base. getindex (r:: UnitRange , s:: IIUR ) =
216+ @propagate_inbounds Base. getindex (r:: UnitRange , s:: IIUR ) =
179217 OffsetArray (r[s. indices], s)
180218
181- @inline @ propagate_inbounds Base. getindex (r:: StepRange , s:: IIUR ) =
219+ @propagate_inbounds Base. getindex (r:: StepRange , s:: IIUR ) =
182220 OffsetArray (r[s. indices], s)
183221
184222@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)
212250
213251# ## Low-level utilities ###
214252
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-
225253indexoffset (r:: AbstractRange ) = first (r) - 1
226254indexoffset (i:: Integer ) = 0
227255indexoffset (i:: Colon ) = 0
228256indexlength (r:: AbstractRange ) = length (r)
229257indexlength (i:: Integer ) = i
230258indexlength (i:: Colon ) = Colon ()
231259
232- @eval @deprecate $ (Symbol (" @unsafe" )) $ (Symbol (" @inbounds" ))
233-
234260function Base. showarg (io:: IO , a:: OffsetArray , toplevel)
235261 print (io, " OffsetArray(" )
236262 Base. showarg (io, parent (a), false )
0 commit comments