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