@@ -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