Skip to content

Commit 6d0389b

Browse files
Merge branch 'master' into master
2 parents 050ad77 + f9fd311 commit 6d0389b

File tree

7 files changed

+69
-30
lines changed

7 files changed

+69
-30
lines changed

.github/workflows/UnitTest.yml

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name: Unit test
22

33
on:
4-
create:
5-
tags:
64
push:
5+
tags:
6+
- 'v*'
77
branches:
88
- master
99
paths-ignore:
@@ -40,27 +40,14 @@ jobs:
4040
julia-arch: x86
4141

4242
steps:
43-
- uses: actions/checkout@v4
44-
- name: "Set up Julia"
45-
uses: julia-actions/[email protected]
43+
- uses: actions/checkout@v6
44+
- uses: julia-actions/setup-julia@v2
4645
with:
4746
version: ${{ matrix.julia-version }}
4847
arch: ${{ matrix.julia-arch }}
49-
50-
- name: Cache artifacts
51-
uses: actions/cache@v4
52-
env:
53-
cache-name: cache-artifacts
54-
with:
55-
path: ~/.julia/artifacts
56-
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
57-
restore-keys: |
58-
${{ runner.os }}-test-${{ env.cache-name }}-
59-
${{ runner.os }}-test-
60-
${{ runner.os }}-
48+
- uses: julia-actions/cache@v2
6149
- name: "Unit Test"
6250
uses: julia-actions/julia-runtest@v1
63-
6451
- uses: julia-actions/julia-processcoverage@v1
6552
- uses: codecov/codecov-action@v5
6653
with:

.github/workflows/docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ jobs:
1818
julia-version: [1]
1919
os: [ubuntu-latest]
2020
steps:
21-
- uses: actions/checkout@v4
21+
- uses: actions/checkout@v6
2222
- uses: julia-actions/setup-julia@latest
2323
with:
2424
version: ${{ matrix.julia-version }}
2525
- name: Cache artifacts
26-
uses: actions/cache@v4
26+
uses: actions/cache@v5
2727
env:
2828
cache-name: cache-artifacts
2929
with:

.github/workflows/invalidations.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ jobs:
88
- uses: julia-actions/setup-julia@v2
99
with:
1010
version: '1.10'
11-
- uses: actions/checkout@v4
11+
- uses: actions/checkout@v6
1212
- uses: julia-actions/julia-buildpkg@latest
1313
- uses: julia-actions/julia-invalidations@v1
1414
id: invs_pr
1515

16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v6
1717
with:
1818
ref: 'master'
1919
- uses: julia-actions/julia-buildpkg@latest

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "OffsetArrays"
22
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
3-
version = "1.16.0"
3+
version = "1.17.0"
44

55
[deps]
66
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

ext/OffsetArraysAdaptExt.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Adapt.adapt_structure(to, O::OffsetArray) = OffsetArrays.parent_call(x -> Adapt.
1111
@static if isdefined(Adapt, :parent_type)
1212
# To support Adapt 3.0 which doesn't have parent_type defined
1313
Adapt.parent_type(::Type{OffsetArray{T,N,AA}}) where {T,N,AA} = AA
14+
Adapt.unwrap_type(W::Type{<:OffsetArray}) = unwrap_type(parent_type(W))
1415
end
1516

1617
end

src/OffsetArrays.jl

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -694,19 +694,60 @@ julia> A
694694
no_offset_view(A::OffsetArray) = no_offset_view(parent(A))
695695
if 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
700742
end
701743
no_offset_view(a::Array) = a
702744
no_offset_view(i::Number) = i
703745
no_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

test/runtests.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,12 @@ Base.getindex(x::PointlessWrapper, i...) = x.parent[i...]
24122412
@test OffsetArrays.no_offset_view(V) == collect(V)
24132413
V = @view O[:,:]
24142414
@test IndexStyle(A) == IndexStyle(O) == IndexStyle(V) == IndexStyle(OffsetArrays.no_offset_view(V)) == IndexLinear()
2415+
2416+
@testset "issue #375" begin
2417+
arr = OffsetArray(reshape(1:15, 3, 5), 2, 3)
2418+
arr_no_offset = OffsetArrays.no_offset_view(@view arr[:, 4])
2419+
@test all(!Base.has_offset_axes, axes(arr_no_offset))
2420+
end
24152421
end
24162422

24172423
@testset "no nesting" begin
@@ -2546,8 +2552,12 @@ end
25462552
@test parent(s_arr) isa SArray
25472553
@test arr == adapt(Array, s_arr)
25482554

2555+
arr2 = OffsetArray(view(rand(5, 5), 2:4, 2:4), -1:1, -1:1)
2556+
25492557
if isdefined(Adapt, :parent_type)
25502558
@test Adapt.parent_type(typeof(arr)) == typeof(arr.parent)
2559+
@test Adapt.unwrap_type(typeof(arr)) == typeof(arr.parent)
2560+
@test Adapt.unwrap_type(typeof(arr2)) == typeof(arr.parent)
25512561
end
25522562
end
25532563

0 commit comments

Comments
 (0)