5
5
# This test file is designed to exercise support for generic indexing,
6
6
# even though offset arrays aren't implemented in Base.
7
7
8
- # OffsetArrays v1.1.3
8
+ # OffsetArrays v1.3.0
9
9
# No compat patch and docstrings
10
- # cherry-pick 1d294f8ea0f6ccd3a2b413535a6e79fac61af728
11
- # cherry-pick reshape bug fix: https://github.com/JuliaArrays/OffsetArrays.jl/pull/151
12
10
module OffsetArrays
13
11
14
- using Base: Indices, tail, @propagate_inbounds
15
- using Base : IdentityUnitRange
12
+ using Base: tail, @propagate_inbounds
13
+ using IdentityUnitRange
16
14
17
15
export OffsetArray, OffsetMatrix, OffsetVector
18
16
@@ -72,9 +70,9 @@ offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange{T} whe
72
70
@inline Base. axes1 (r:: IdOffsetRange ) = IdOffsetRange (Base. axes1 (r. parent), r. offset)
73
71
@inline Base. unsafe_indices (r:: IdOffsetRange ) = (r,)
74
72
@inline Base. length (r:: IdOffsetRange ) = length (r. parent)
75
- Base . reduced_index (i :: IdOffsetRange ) = typeof (i)( first (i) : first (i))
76
- # Workaround for #92 on Julia < 1.4
77
- Base . reduced_index (i :: IdentityUnitRange{<:IdOffsetRange} ) = typeof (i)( first (i) : first (i))
73
+ for f in [ :firstindex , :lastindex ]
74
+ @eval Base. $ f (r :: IdOffsetRange ) = $ f (r . parent) .+ r . offset
75
+ end
78
76
79
77
@inline function Base. iterate (r:: IdOffsetRange )
80
78
ret = iterate (r. parent)
94
92
@propagate_inbounds function Base. getindex (r:: IdOffsetRange , s:: AbstractUnitRange{<:Integer} )
95
93
return r. parent[s .- r. offset] .+ r. offset
96
94
end
97
- @propagate_inbounds function Base. getindex (r:: IdOffsetRange , s:: IdOffsetRange )
95
+ @propagate_inbounds function Base. getindex (r:: IdOffsetRange , s:: IdentityUnitRange )
98
96
return IdOffsetRange (r. parent[s .- r. offset], r. offset)
99
97
end
98
+ @propagate_inbounds function Base. getindex (r:: IdOffsetRange , s:: IdOffsetRange )
99
+ return IdOffsetRange (r. parent[s. parent .+ (s. offset - r. offset)] .+ (r. offset - s. offset), s. offset)
100
+ end
100
101
101
102
# offset-preserve broadcasting
102
103
Broadcast. broadcasted (:: Base.Broadcast.DefaultArrayStyle{1} , :: typeof (- ), r:: IdOffsetRange{T} , x:: Integer ) where T =
@@ -106,67 +107,156 @@ Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(+), r::IdO
106
107
Broadcast. broadcasted (:: Base.Broadcast.DefaultArrayStyle{1} , :: typeof (+ ), x:: Integer , r:: IdOffsetRange{T} ) where T =
107
108
IdOffsetRange {T} (x .+ r. parent, r. offset)
108
109
109
- Base. show (io:: IO , r:: IdOffsetRange ) = print (io, " OffsetArrays.IdOffsetRange(" ,first (r), ' :' , last (r)," )" )
110
+ Base. show (io:: IO , r:: IdOffsetRange ) = print (io, " OffsetArrays.IdOffsetRange(" , first (r), ' :' , last (r), " )" )
110
111
111
112
# Optimizations
112
113
@inline Base. checkindex (:: Type{Bool} , inds:: IdOffsetRange , i:: Real ) = Base. checkindex (Bool, inds. parent, i - inds. offset)
113
114
115
+ struct Origin{T <: Union{Tuple,Int} }
116
+ index:: T
117
+ end
118
+ Origin (I:: NTuple{N,Int} ) where N = Origin {typeof(I)} (I)
119
+ Origin (I:: CartesianIndex ) = Origin (I. I)
120
+ Origin (I1:: Int , In:: Int... ) = Origin ((I1, In... ))
121
+ # Origin(0) != Origin((0, )) but they work the same with broadcasting
122
+ Origin (n:: Int ) = Origin {Int} (n)
123
+
124
+ (o:: Origin )(A:: AbstractArray ) = o. index .- first .(axes (A))
125
+
126
+ # ## Low-level utilities ###
127
+
128
+ _indexoffset (r:: AbstractRange ) = first (r) - 1
129
+ _indexoffset (i:: Integer ) = 0
130
+ _indexoffset (i:: Colon ) = 0
131
+ _indexlength (r:: AbstractRange ) = length (r)
132
+ _indexlength (i:: Integer ) = i
133
+ _indexlength (i:: Colon ) = Colon ()
134
+
135
+ _offset (axparent:: AbstractUnitRange , ax:: AbstractUnitRange ) = first (ax) - first (axparent)
136
+ _offset (axparent:: AbstractUnitRange , ax:: Integer ) = 1 - first (axparent)
137
+
138
+ abstract type AxisConversionStyle end
139
+ struct SingleRange <: AxisConversionStyle end
140
+ struct TupleOfRanges <: AxisConversionStyle end
141
+
142
+ AxisConversionStyle (:: Type ) = SingleRange ()
143
+ AxisConversionStyle (:: Type{<:CartesianIndices} ) = TupleOfRanges ()
144
+
145
+ _convertTupleAbstractUnitRange (x) = _convertTupleAbstractUnitRange (AxisConversionStyle (typeof (x)), x)
146
+ _convertTupleAbstractUnitRange (:: SingleRange , x) = (convert (AbstractUnitRange{Int}, x),)
147
+ _convertTupleAbstractUnitRange (:: TupleOfRanges , x) = convert (Tuple{Vararg{AbstractUnitRange{Int}}}, x)
148
+
149
+ _toAbstractUnitRanges (t:: Tuple ) = (_convertTupleAbstractUnitRange (first (t))... , _toAbstractUnitRanges (tail (t))... )
150
+ _toAbstractUnitRanges (:: Tuple{} ) = ()
151
+
152
+ # ensure that the indices are consistent in the constructor
153
+ _checkindices (A:: AbstractArray , indices, label) = _checkindices (ndims (A), indices, label)
154
+ function _checkindices (N:: Integer , indices, label)
155
+ throw_argumenterror (N, indices, label) = throw (ArgumentError (label * " $indices are not compatible with a $(N) D array" ))
156
+ N == length (indices) || throw_argumenterror (N, indices, label)
157
+ end
158
+
159
+
160
+ # Technically we know the length of CartesianIndices but we need to convert it first, so here we
161
+ # don't put it in OffsetAxisKnownLength.
162
+ const OffsetAxisKnownLength = Union{Integer,AbstractUnitRange}
163
+ const OffsetAxis = Union{OffsetAxisKnownLength,Colon}
164
+ const ArrayInitializer = Union{UndefInitializer,Missing,Nothing}
165
+
114
166
# # OffsetArray
115
167
struct OffsetArray{T,N,AA<: AbstractArray } <: AbstractArray{T,N}
116
168
parent:: AA
117
169
offsets:: NTuple{N,Int}
170
+ function OffsetArray {T,N,AA} (parent:: AA , offsets:: NTuple{N,Int} ) where {T,N,AA <: AbstractArray }
171
+ @boundscheck overflow_check .(axes (parent), offsets)
172
+ new {T,N,AA} (parent, offsets)
173
+ end
118
174
end
119
- OffsetVector{T,AA<: AbstractArray } = OffsetArray{T,1 ,AA}
120
- OffsetMatrix{T,AA<: AbstractArray } = OffsetArray{T,2 ,AA}
121
175
122
- # # OffsetArray constructors
176
+ const OffsetVector{T,AA <: AbstractArray } = OffsetArray{T,1 ,AA}
177
+
178
+ const OffsetMatrix{T,AA <: AbstractArray } = OffsetArray{T,2 ,AA}
123
179
124
- offset (axparent:: AbstractUnitRange , ax:: AbstractUnitRange ) = first (ax) - first (axparent)
125
- offset (axparent:: AbstractUnitRange , ax:: Integer ) = 1 - first (axparent)
180
+ function overflow_check (r, offset:: T ) where T
181
+ # This gives some performance boost https://github.com/JuliaLang/julia/issues/33273
182
+ throw_upper_overflow_error () = throw (ArgumentError (" Boundary overflow detected: offset $offset should be equal or less than $(typemax (T) - last (r)) " ))
183
+ throw_lower_overflow_error () = throw (ArgumentError (" Boundary overflow detected: offset $offset should be equal or greater than $(typemin (T) - first (r)) " ))
126
184
127
- function OffsetArray (A:: AbstractArray{T,N} , offsets:: NTuple{N,Int} ) where {T,N}
128
- OffsetArray {T,N,typeof(A)} (A, offsets)
185
+ if offset > 0 && last (r) > typemax (T) - offset
186
+ throw_upper_overflow_error ()
187
+ elseif offset < 0 && first (r) < typemin (T) - offset
188
+ throw_lower_overflow_error ()
189
+ end
129
190
end
130
- OffsetArray (A:: AbstractArray{T,0} , offsets:: Tuple{} ) where T =
131
- OffsetArray {T,0,typeof(A)} (A, ())
132
191
133
- OffsetArray (A:: AbstractArray{T,N} , offsets:: Vararg{Int,N} ) where {T,N} =
134
- OffsetArray (A, offsets)
135
- OffsetArray (A:: AbstractArray{T,0} ) where {T} = OffsetArray (A, ())
192
+ # Tuples of integers are treated as offsets
193
+ # Empty Tuples are handled here
194
+ function OffsetArray (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} )
195
+ _checkindices (A, offsets, " offsets" )
196
+ OffsetArray {eltype(A),ndims(A),typeof(A)} (A, offsets)
197
+ end
136
198
137
- const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
138
- OffsetArray {T,N} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} =
139
- OffsetArray (Array {T,N} (init, map (indexlength, inds)), map (indexoffset, inds))
140
- OffsetArray {T} (init:: ArrayInitializer , inds:: Indices{N} ) where {T,N} = OffsetArray {T,N} (init, inds)
141
- OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
142
- OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} = OffsetArray {T,N} (init, inds)
199
+ # These methods are necessary to disallow incompatible dimensions for
200
+ # the OffsetVector and the OffsetMatrix constructors
201
+ for (FT, ND) in ((:OffsetVector , :1 ), (:OffsetMatrix , :2 ))
202
+ @eval function $FT (A:: AbstractArray{<:Any,$ND} , offsets:: Tuple{Vararg{Integer}} )
203
+ _checkindices (A, offsets, " offsets" )
204
+ OffsetArray {eltype(A),$ND,typeof(A)} (A, offsets)
205
+ end
206
+ FTstr = string (FT)
207
+ @eval function $FT (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} )
208
+ throw (ArgumentError ($ FTstr * " requires a " * string ($ ND) * " D array" ))
209
+ end
210
+ end
143
211
144
- # OffsetVector constructors
145
- OffsetVector (A:: AbstractVector , offset) = OffsetArray (A, offset)
146
- OffsetVector {T} (init:: ArrayInitializer , inds:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds)
212
+ # # OffsetArray constructors
213
+ for FT in (:OffsetArray , :OffsetVector , :OffsetMatrix )
214
+ # Nested OffsetArrays may strip off the wrapper and collate the offsets
215
+ @eval function $FT (A:: OffsetArray , offsets:: Tuple{Vararg{Integer}} )
216
+ _checkindices (A, offsets, " offsets" )
217
+ $ FT (parent (A), map (+ , A. offsets, offsets))
218
+ end
219
+
220
+ # In general, indices get converted to AbstractUnitRanges.
221
+ # CartesianIndices{N} get converted to N ranges
222
+ @eval function $FT (A:: AbstractArray , inds:: Tuple{Any,Vararg{Any}} )
223
+ $ FT (A, _toAbstractUnitRanges (to_indices (A, axes (A), inds)))
224
+ end
225
+
226
+ # convert ranges to offsets
227
+ @eval function $FT (A:: AbstractArray , inds:: Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}} )
228
+ _checkindices (A, inds, " indices" )
229
+ # Performance gain by wrapping the error in a function: see https://github.com/JuliaLang/julia/issues/37558
230
+ throw_dimerr (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" ))
231
+ lA = size (A)
232
+ lI = map (length, inds)
233
+ lA == lI || throw_dimerr (lA, lI)
234
+ $ FT (A, map (_offset, axes (A), inds))
235
+ end
147
236
148
- # OffsetMatrix constructors
149
- OffsetMatrix (A:: AbstractMatrix , offset1, offset2) = OffsetArray (A, offset1, offset2)
150
- OffsetMatrix {T} (init:: ArrayInitializer , inds1:: AbstractUnitRange , inds2:: AbstractUnitRange ) where {T} = OffsetArray {T} (init, inds1, inds2)
237
+ @eval $ FT (A:: AbstractArray , inds:: Vararg ) = $ FT (A, inds)
151
238
152
- function OffsetArray (A:: AbstractArray{T,N} , inds:: NTuple{N,AbstractUnitRange} ) where {T,N}
153
- axparent = axes (A)
154
- lA = map (length, axparent)
155
- lI = map (length, inds)
156
- 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" ))
157
- OffsetArray (A, map (offset, axparent, inds))
239
+ @eval $ FT (A:: AbstractArray , origin:: Origin ) = $ FT (A, origin (A))
158
240
end
159
- OffsetArray (A:: AbstractArray{T,N} , inds:: Vararg{AbstractUnitRange,N} ) where {T,N} =
160
- OffsetArray (A, inds)
161
241
162
- # avoid a level of indirection when nesting OffsetArrays
163
- function OffsetArray (A:: OffsetArray , offsets:: NTuple{N,Int} ) where {N}
164
- OffsetArray (parent (A), offsets .+ A. offsets)
242
+ # array initialization
243
+ function OffsetArray {T,N} (init:: ArrayInitializer , inds:: Tuple{Vararg{OffsetAxisKnownLength}} ) where {T,N}
244
+ _checkindices (N, inds, " indices" )
245
+ AA = Array {T,N} (init, map (_indexlength, inds))
246
+ OffsetArray {T,N,typeof(AA)} (AA, map (_indexoffset, inds))
165
247
end
166
- OffsetArray (A:: OffsetArray{T,0} , inds:: Tuple{} ) where {T} = OffsetArray (parent (A), ())
167
- # OffsetArray(A::OffsetArray{T,N}, inds::Tuple{}) where {T,N} = error("this should never be called")
248
+ function OffsetArray {T,N} (init:: ArrayInitializer , inds:: Tuple ) where {T,N}
249
+ OffsetArray {T,N} (init, _toAbstractUnitRanges (inds))
250
+ end
251
+ OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg ) where {T,N} = OffsetArray {T,N} (init, inds)
252
+
253
+ OffsetArray {T} (init:: ArrayInitializer , inds:: NTuple{N,OffsetAxisKnownLength} ) where {T,N} = OffsetArray {T,N} (init, inds)
254
+ function OffsetArray {T} (init:: ArrayInitializer , inds:: Tuple ) where {T}
255
+ OffsetArray {T} (init, _toAbstractUnitRanges (inds))
256
+ end
257
+ OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg ) where {T} = OffsetArray {T} (init, inds)
168
258
169
- Base. IndexStyle (:: Type{OA} ) where {OA<: OffsetArray } = IndexStyle (parenttype (OA))
259
+ Base. IndexStyle (:: Type{OA} ) where {OA <: OffsetArray } = IndexStyle (parenttype (OA))
170
260
parenttype (:: Type{OffsetArray{T,N,AA}} ) where {T,N,AA} = AA
171
261
parenttype (A:: OffsetArray ) = parenttype (typeof (A))
172
262
@@ -182,27 +272,24 @@ Base.eachindex(::IndexLinear, A::OffsetVector) = axes(A, 1)
182
272
@inline Base. axes (A:: OffsetArray , d) = d <= ndims (A) ? IdOffsetRange (axes (parent (A), d), A. offsets[d]) : IdOffsetRange (axes (parent (A), d))
183
273
@inline Base. axes1 (A:: OffsetArray{T,0} ) where {T} = IdOffsetRange (axes (parent (A), 1 )) # we only need to specialize this one
184
274
185
- const OffsetAxisKnownLength = Union{Integer, UnitRange, Base. OneTo, IdentityUnitRange, IdOffsetRange}
186
-
187
275
Base. similar (A:: OffsetArray , :: Type{T} , dims:: Dims ) where T =
188
276
similar (parent (A), T, dims)
189
277
function Base. similar (A:: AbstractArray , :: Type{T} , inds:: Tuple{OffsetAxisKnownLength,Vararg{OffsetAxisKnownLength}} ) where T
190
- B = similar (A, T, map (indexlength , inds))
191
- return OffsetArray (B, map (offset , axes (B), inds))
278
+ B = similar (A, T, map (_indexlength , inds))
279
+ return OffsetArray (B, map (_offset , axes (B), inds))
192
280
end
193
281
194
282
# reshape accepts a single colon
195
- const OffsetAxis = Union{OffsetAxisKnownLength, Colon}
196
283
Base. reshape (A:: AbstractArray , inds:: OffsetAxis... ) = reshape (A, inds)
197
284
function Base. reshape (A:: AbstractArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} )
198
- AR = reshape (A, map (indexlength , inds))
199
- return OffsetArray (AR, map (offset , axes (AR), inds))
285
+ AR = reshape (A, map (_indexlength , inds))
286
+ return OffsetArray (AR, map (_offset , axes (AR), inds))
200
287
end
201
288
202
289
# Reshaping OffsetArrays can "pop" the original OffsetArray wrapper and return
203
290
# an OffsetArray(reshape(...)) instead of an OffsetArray(reshape(OffsetArray(...)))
204
291
Base. reshape (A:: OffsetArray , inds:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) =
205
- OffsetArray (reshape (parent (A), map (indexlength , inds)), map (indexoffset , inds))
292
+ OffsetArray (reshape (parent (A), map (_indexlength , inds)), map (_indexoffset , inds))
206
293
# And for non-offset axes, we can just return a reshape of the parent directly
207
294
Base. reshape (A:: OffsetArray , inds:: Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}} ) = reshape (parent (A), inds)
208
295
Base. reshape (A:: OffsetArray , inds:: Dims ) = reshape (parent (A), inds)
@@ -211,9 +298,9 @@ Base.reshape(A::OffsetVector, ::Colon) = A
211
298
Base. reshape (A:: OffsetArray , inds:: Union{Int,Colon} ...) = reshape (parent (A), inds)
212
299
Base. reshape (A:: OffsetArray , inds:: Tuple{Vararg{Union{Int,Colon}}} ) = reshape (parent (A), inds)
213
300
214
- function Base. similar (:: Type{T} , shape:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where {T<: AbstractArray }
215
- P = T (undef, map (indexlength , shape))
216
- OffsetArray (P, map (offset , axes (P), shape))
301
+ function Base. similar (:: Type{T} , shape:: Tuple{OffsetAxis,Vararg{OffsetAxis}} ) where {T <: AbstractArray }
302
+ P = T (undef, map (_indexlength , shape))
303
+ OffsetArray (P, map (_offset , axes (P), shape))
217
304
end
218
305
219
306
Base. fill (v, inds:: NTuple{N, Union{Integer, AbstractUnitRange}} ) where {N} =
@@ -276,22 +363,29 @@ const IIUR = IdentityUnitRange{S} where S<:AbstractUnitRange{T} where T<:Integer
276
363
277
364
Base. step (a:: OffsetRange ) = step (parent (a))
278
365
279
- Base. getindex (a:: OffsetRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
280
- Base. getindex (a:: OffsetRange , r:: AbstractRange ) = a. parent[r .- a. offsets[1 ]]
281
- Base. getindex (a:: AbstractRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
366
+ @propagate_inbounds Base. getindex (a:: OffsetRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
367
+ @propagate_inbounds function Base. getindex (a:: OffsetRange , r:: IdOffsetRange )
368
+ OffsetArray (a. parent[r. parent .+ (r. offset - a. offsets[1 ])], r. offset)
369
+ end
370
+ @propagate_inbounds Base. getindex (r:: OffsetRange , s:: IIUR ) =
371
+ OffsetArray (r[s. indices], s)
372
+ @propagate_inbounds Base. getindex (a:: OffsetRange , r:: AbstractRange ) = a. parent[r .- a. offsets[1 ]]
373
+ @propagate_inbounds Base. getindex (a:: AbstractRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], r. offsets)
282
374
283
375
@propagate_inbounds Base. getindex (r:: UnitRange , s:: IIUR ) =
284
376
OffsetArray (r[s. indices], s)
285
377
286
378
@propagate_inbounds Base. getindex (r:: StepRange , s:: IIUR ) =
287
379
OffsetArray (r[s. indices], s)
288
380
289
- @inline @propagate_inbounds Base. getindex (r:: StepRangeLen{T,<:Base.TwicePrecision,<:Base.TwicePrecision} , s:: IIUR ) where T =
381
+ # this method is needed for ambiguity resolution
382
+ @propagate_inbounds Base. getindex (r:: StepRangeLen{T,<:Base.TwicePrecision,<:Base.TwicePrecision} , s:: IIUR ) where T =
290
383
OffsetArray (r[s. indices], s)
291
- @inline @propagate_inbounds Base. getindex (r:: StepRangeLen{T} , s:: IIUR ) where {T} =
384
+
385
+ @propagate_inbounds Base. getindex (r:: StepRangeLen{T} , s:: IIUR ) where {T} =
292
386
OffsetArray (r[s. indices], s)
293
387
294
- @inline @ propagate_inbounds Base. getindex (r:: LinRange , s:: IIUR ) =
388
+ @propagate_inbounds Base. getindex (r:: LinRange , s:: IIUR ) =
295
389
OffsetArray (r[s. indices], s)
296
390
297
391
function Base. show (io:: IO , r:: OffsetRange )
@@ -306,18 +400,11 @@ Base.show(io::IO, ::MIME"text/plain", r::OffsetRange) = show(io, r)
306
400
Base. resize! (A:: OffsetVector , nl:: Integer ) = (resize! (A. parent, nl); A)
307
401
Base. push! (A:: OffsetVector , x... ) = (push! (A. parent, x... ); A)
308
402
Base. pop! (A:: OffsetVector ) = pop! (A. parent)
403
+ Base. append! (A:: OffsetVector , items) = (append! (A. parent, items); A)
309
404
Base. empty! (A:: OffsetVector ) = (empty! (A. parent); A)
310
405
311
- # ## Low-level utilities ###
312
-
313
- indexoffset (r:: AbstractRange ) = first (r) - 1
314
- indexoffset (i:: Integer ) = 0
315
- indexoffset (i:: Colon ) = 0
316
- indexlength (r:: AbstractRange ) = length (r)
317
- indexlength (i:: Integer ) = i
318
- indexlength (i:: Colon ) = Colon ()
319
-
320
- function Base. inds2string (inds:: Tuple {Vararg{Union{IdOffsetRange, IdentityUnitRange{<: IdOffsetRange }}}})
406
+ # These functions keep the summary compact
407
+ function Base. inds2string (inds:: Tuple {Vararg{Union{IdOffsetRange,IdentityUnitRange{<: IdOffsetRange }}}})
321
408
Base. inds2string (map (UnitRange, inds))
322
409
end
323
410
Base. showindices (io:: IO , ind1:: IdOffsetRange , inds:: IdOffsetRange... ) = Base. showindices (io, map (UnitRange, (ind1, inds... ))... )
0 commit comments