@@ -694,19 +694,60 @@ julia> A
694694no_offset_view(A:: OffsetArray ) = no_offset_view(parent(A))
695695if isdefined(Base, :IdentityUnitRange)
696696 # valid only if Slice is distinguished from IdentityUnitRange
697- no_offset_view(a:: Base.Slice{<:Base.OneTo} ) = a
698- no_offset_view(a:: Base.Slice ) = Base. Slice(UnitRange(a))
699- no_offset_view(S:: SubArray ) = view(parent(S), map(no_offset_view, parentindices(S)). .. )
697+ _onebasedslice(S:: Base.Slice ) = Base. Slice(Base. OneTo(length(S)))
698+ _onebasedslice(S:: Base.Slice{<:Base.OneTo} ) = S
699+ _onebasedslice(S) = S
700+ _isoffsetslice(:: Any ) = false
701+ _isoffsetslice(:: Base.Slice ) = true
702+ _isoffsetslice(:: Base.Slice{<:Base.OneTo} ) = false
703+ function no_offset_view(S:: SubArray )
704+ #= If a view contains an offset Slice axis,
705+ i.e. it is a view of an offset array along the offset axis,
706+ we shift the axis to a 1-based one.
707+ E.g. Slice(2:3) -> Slice(Base.OneTo(2))
708+ We transform the `parent` as well as the `parentindices`,
709+ so that the view still points to the same elements, even though the indices have changed.
710+ This way, we retain the axis of the view as a `Slice`
711+ =#
712+ P = parent(S)
713+ pinds = parentindices(S)
714+ #=
715+ Check if all the axes are `Slice`s and the parent has `OneTo` axes,
716+ in which case we may unwrap the `OffsetArray` and forward the view to the parent.
717+ =#
718+ may_pop_parent = all(_isoffsetslice, pinds) && P isa OffsetArray && all(x -> x isa Base. OneTo, axes(parent(P)))
719+ if may_pop_parent
720+ return no_offset_view(P)
721+ end
722+ #=
723+ we convert offset `Slice`s to 1-based ones using `_onebasedslice`.
724+ The next call, `no_offset_view`, is a no-op on a `Slice{<:OneTo}`,
725+ while it converts the offset axes to 1-based ones.
726+ Eventually, we end up with a `Tuple` comprising `Slice{<:OneTo}`s and other 1-based axes.
727+
728+ The difference between `_onebasedslice` and `no_offset_view` is that
729+ the latter does not change the value of the range, while the former does.
730+ =#
731+ newviewinds = map(no_offset_view ∘ _onebasedslice, pinds)
732+ needs_shifting = any(_isoffsetslice, pinds)
733+ P_maybeshiftedinds = if needs_shifting
734+ t = Origin(parent(S)). index
735+ neworigin = ntuple(i -> _isoffsetslice(pinds[i]) ? 1 : t[i], length(t))
736+ Origin(neworigin)(P)
737+ else
738+ P
739+ end
740+ view(P_maybeshiftedinds, newviewinds... )
741+ end
700742end
701743no_offset_view(a:: Array ) = a
702744no_offset_view(i:: Number ) = i
703745no_offset_view(A:: AbstractArray ) = _no_offset_view(axes(A), A)
704746_no_offset_view(:: Tuple{} , A:: AbstractArray{T,0} ) where T = A
705747_no_offset_view(:: Tuple{Base.OneTo, Vararg{Base.OneTo}} , A:: AbstractArray ) = A
706- # the following method is needed for ambiguity resolution
707- _no_offset_view(:: Tuple{Base.OneTo, Vararg{Base.OneTo}} , A:: AbstractUnitRange ) = A
708- _no_offset_view(:: Any , A:: AbstractArray ) = OffsetArray(A, Origin(1 ))
709- _no_offset_view(:: Any , A:: AbstractUnitRange ) = UnitRange(A)
748+ _no_offset_view(:: Any , A:: AbstractArray ) = _no_offset_view(A)
749+ _no_offset_view(A:: AbstractArray ) = OffsetArray(A, Origin(1 ))
750+ _no_offset_view(A:: AbstractUnitRange ) = UnitRange(A)
710751
711752# ####
712753# center/centered
0 commit comments