@@ -392,44 +392,92 @@ Broadcast.broadcast_unalias(dest::OffsetArray, src::OffsetArray) = parent(dest)
392
392
393
393
# ## Special handling for AbstractRange
394
394
395
- const OffsetRange{T} = OffsetArray{T, 1 ,<: AbstractRange{T} }
396
- const OffsetUnitRange{T} = OffsetArray{T, 1 ,<: AbstractUnitRange{T} }
395
+ const OffsetRange{T} = OffsetVector{T ,<: AbstractRange{T} }
396
+ const OffsetUnitRange{T} = OffsetVector{T ,<: AbstractUnitRange{T} }
397
397
const IIUR = IdentityUnitRange{S} where S<: AbstractUnitRange{T} where T<: Integer
398
398
399
399
Base. step (a:: OffsetRange ) = step (parent (a))
400
400
401
- @propagate_inbounds function Base. getindex (a:: OffsetRange , r:: OffsetRange )
402
- OffsetArray (a. parent[r. parent .- a. offsets[1 ]], axes (r))
401
+ Base. checkindex (:: Type{Bool} , inds:: AbstractUnitRange , or:: OffsetRange ) = Base. checkindex (Bool, inds, parent (or))
402
+
403
+ # Certain special methods for linear indexing with integer ranges (or OffsetRanges)
404
+ # These may bypass the default getindex(A, I...) pathway if the parent types permit this
405
+ # For example AbstractUnitRanges and Arrays have special linear indexing behavior defined
406
+
407
+ # If both the arguments are offset, we may unwrap the indices to call (::OffsetArray)[::AbstractRange{Int}]
408
+ @propagate_inbounds function Base. getindex (A:: OffsetArray , r:: OffsetRange{Int} )
409
+ _maybewrapoffset (A[parent (r)], axes (r))
410
+ end
411
+ # If the indices are offset, we may unwrap them and pass the parent to getindex
412
+ @propagate_inbounds function Base. getindex (A:: AbstractRange , r:: OffsetRange{Int} )
413
+ _maybewrapoffset (A[parent (r)], axes (r))
414
+ end
415
+
416
+ # An OffsetUnitRange might use the rapid getindex(::Array, ::AbstractUnitRange{Int}) for contiguous indexing
417
+ @propagate_inbounds function Base. getindex (A:: Array , r:: OffsetUnitRange{Int} )
418
+ B = A[_contiguousindexingtype (parent (r))]
419
+ OffsetArray (B, axes (r))
420
+ end
421
+
422
+ # avoid hitting the slow method getindex(::Array, ::AbstractRange{Int})
423
+ # instead use the faster getindex(::Array, ::UnitRange{Int})
424
+ @propagate_inbounds function Base. getindex (A:: Array , r:: Union{IdOffsetRange, IIUR} )
425
+ B = A[_contiguousindexingtype (r)]
426
+ _maybewrapoffset (B, axes (r))
403
427
end
404
- @propagate_inbounds function Base. getindex (a:: OffsetRange , r:: IdOffsetRange )
405
- OffsetArray (a. parent[r. parent .+ (r. offset - a. offsets[1 ])], axes (r))
428
+
429
+ # Linear Indexing of OffsetArrays with AbstractUnitRanges may use the faster contiguous indexing methods
430
+ @inline function Base. getindex (A:: OffsetArray , r:: AbstractUnitRange{Int} )
431
+ @boundscheck checkbounds (A, r)
432
+ # nD OffsetArrays do not have their linear indices shifted, so we may forward the indices provided to the parent
433
+ @inbounds B = parent (A)[_contiguousindexingtype (r)]
434
+ _maybewrapoffset (B, axes (r))
435
+ end
436
+ @inline function Base. getindex (A:: OffsetVector , r:: AbstractUnitRange{Int} )
437
+ @boundscheck checkbounds (A, r)
438
+ # OffsetVectors may have their linear indices shifted, so we subtract the offset from the indices provided
439
+ @inbounds B = parent (A)[_subtractoffset (r, A. offsets[1 ])]
440
+ _maybewrapoffset (B, axes (r))
441
+ end
442
+
443
+ # This method added mainly to index an OffsetRange with another range
444
+ @inline function Base. getindex (A:: OffsetVector , r:: AbstractRange{Int} )
445
+ @boundscheck checkbounds (A, r)
446
+ @inbounds B = parent (A)[_subtractoffset (r, A. offsets[1 ])]
447
+ _maybewrapoffset (B, axes (r))
448
+ end
449
+
450
+ # In general we would pass through getindex(A, I...) which calls to_indices(A, I) and finally to_index(I)
451
+ # An OffsetUnitRange{Int} has an equivalent IdOffsetRange with the same values and axes,
452
+ # something similar also holds for OffsetUnitRange{BigInt}
453
+ # We may replace the former with the latter in an indexing operation to obtain a performance boost
454
+ @inline function Base. to_index (r:: OffsetUnitRange{<:Union{Int,BigInt}} )
455
+ of = first (axes (r,1 )) - 1
456
+ IdOffsetRange (_subtractoffset (parent (r), of), of)
406
457
end
407
- @propagate_inbounds Base. getindex (a:: OffsetRange , r:: AbstractRange ) = _maybewrapaxes (a. parent[r .- a. offsets[1 ]], axes (r,1 ))
408
- @propagate_inbounds Base. getindex (a:: AbstractRange , r:: OffsetRange ) = OffsetArray (a[parent (r)], axes (r))
409
458
410
459
for OR in [:IIUR , :IdOffsetRange ]
411
460
for R in [:StepRange , :StepRangeLen , :LinRange , :UnitRange ]
412
- @eval @propagate_inbounds Base. getindex (r:: $R , s:: $OR ) = OffsetArray (r[UnitRange (s)], axes (s))
461
+ @eval @inline function Base. getindex (r:: $R , s:: $OR )
462
+ @boundscheck checkbounds (r, s)
463
+ @inbounds pr = r[UnitRange (s)]
464
+ _maybewrapoffset (pr, axes (s,1 ))
465
+ end
413
466
end
414
467
415
468
# this method is needed for ambiguity resolution
416
- @eval @propagate_inbounds Base. getindex (r:: StepRangeLen{T,<:Base.TwicePrecision,<:Base.TwicePrecision} , s:: $OR ) where T =
417
- OffsetArray (r[UnitRange (s)], axes (s))
418
-
419
- #= Integer UnitRanges may return an appropriate AbstractUnitRange{<:Integer}, as the result may be used in indexing, and
420
- indexing is faster with ranges =#
421
- @eval @propagate_inbounds function Base. getindex (r:: UnitRange{<:Integer} , s:: $OR )
422
- rs = r[UnitRange (s)]
423
- offset_s = first (axes (s,1 )) - 1
424
- IdOffsetRange (UnitRange (rs .- offset_s), offset_s)
469
+ @eval @inline function Base. getindex (r:: StepRangeLen{T,<:Base.TwicePrecision,<:Base.TwicePrecision} , s:: $OR ) where T
470
+ @boundscheck checkbounds (r, s)
471
+ @inbounds pr = r[UnitRange (s)]
472
+ _maybewrapoffset (pr, axes (s,1 ))
425
473
end
426
474
end
427
475
428
476
# mapreduce is faster with an IdOffsetRange than with an OffsetUnitRange
429
477
# We therefore convert OffsetUnitRanges to IdOffsetRanges with the same values and axes
430
478
function Base. mapreduce (f, op, As:: OffsetUnitRange{<:Integer} ...; kw... )
431
479
ofs = map (A -> first (axes (A,1 )) - 1 , As)
432
- AIds = map ((A, of) -> IdOffsetRange (UnitRange (parent (A)) .- of , of), As, ofs)
480
+ AIds = map ((A, of) -> IdOffsetRange (_subtractoffset (parent (A), of) , of), As, ofs)
433
481
mapreduce (f, op, AIds... ; kw... )
434
482
end
435
483
0 commit comments