Skip to content

Commit e81e6d9

Browse files
committed
add more test cases for OffsetArray constructors
1 parent a5b8e2c commit e81e6d9

File tree

3 files changed

+353
-174
lines changed

3 files changed

+353
-174
lines changed

src/OffsetArrays.jl

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ include("utils.jl")
1414

1515
# Technically we know the length of CartesianIndices but we need to convert it first, so here we
1616
# don't put it in OffsetAxisKnownLength.
17-
const OffsetAxisKnownLength = Union{Integer, UnitRange, Base.OneTo, IdentityUnitRange, IdOffsetRange}
17+
# TODO: add CartesianIndices to OffsetAxisKnownLength
18+
const OffsetAxisKnownLength = Union{Integer, AbstractUnitRange, IdOffsetRange}
1819
const OffsetAxis = Union{OffsetAxisKnownLength, CartesianIndices, Colon}
1920
const ArrayInitializer = Union{UndefInitializer, Missing, Nothing}
2021

@@ -96,7 +97,7 @@ end
9697
for FT in (:OffsetArray, :OffsetVector, :OffsetMatrix)
9798
# The only route out to inner constructor
9899
@eval function $FT(A::AbstractArray{T}, offsets::NTuple{N, Integer}) where {T, N}
99-
ndims(A) == N || throw(DimensionMismatch("The number of offsets should equal ndims(A) = $(ndims(A))"))
100+
ndims(A) == N || throw(DimensionMismatch("The number of offsets $(N) should equal ndims(A) = $(ndims(A))"))
100101
OffsetArray{T, ndims(A), typeof(A)}(A, offsets)
101102
end
102103
# nested OffsetArrays
@@ -119,32 +120,25 @@ for FT in (:OffsetArray, :OffsetVector, :OffsetMatrix)
119120
end
120121

121122
# array initialization
122-
OffsetArray{T,N}(init::ArrayInitializer, inds::NTuple{N, OffsetAxisKnownLength}) where {T,N} =
123-
OffsetArray(Array{T,N}(init, map(_indexlength, inds)), map(_indexoffset, inds))
124-
OffsetArray{T,N}(init::ArrayInitializer, inds::Vararg{OffsetAxisKnownLength,N}) where {T,N} = OffsetArray{T,N}(init, inds)
125-
function OffsetArray{T, N}(init::ArrayInitializer, inds::NTuple{N, Union{OffsetAxisKnownLength, CartesianIndices}}) where {T, N}
126-
OffsetArray{T, N}(init, _expandCartesianIndices(inds))
123+
function OffsetArray{T,N}(init::ArrayInitializer, inds::NTuple{N, OffsetAxisKnownLength}) where {T,N}
124+
AA = Array{T,N}(init, map(_indexlength, inds))
125+
OffsetArray{T, N, typeof(AA)}(AA, map(_indexoffset, inds))
127126
end
128-
function OffsetArray{T, N}(init::ArrayInitializer, inds::Vararg{Union{OffsetAxisKnownLength, CartesianIndices}}) where {T, N}
129-
OffsetArray{T, N}(init, inds)
130-
end
131-
function OffsetArray{T, N}(init::ArrayInitializer, inds::CartesianIndices{N}) where {T,N}
132-
OffsetArray{T, N}(init, convert(Tuple{Vararg{AbstractUnitRange{Int}}}, inds))
127+
function OffsetArray{T, N}(init::ArrayInitializer, inds::NTuple{NT, Union{OffsetAxisKnownLength, CartesianIndices}}) where {T, N, NT}
128+
# NT is probably not the actual dimension of the array; CartesianIndices might contain multiple dimensions
129+
indsN = _expandCartesianIndices(inds)
130+
length(indsN) == N || throw(DimensionMismatch("The number of offsets $(length(indsN)) should equal ndims(A) = $N"))
131+
OffsetArray{T, N}(init, indsN)
133132
end
133+
OffsetArray{T,N}(init::ArrayInitializer, inds::Union{OffsetAxisKnownLength, CartesianIndices}...) where {T,N} = OffsetArray{T,N}(init, inds)
134134

135135
OffsetArray{T}(init::ArrayInitializer, inds::NTuple{N, OffsetAxisKnownLength}) where {T,N} = OffsetArray{T,N}(init, inds)
136-
OffsetArray{T}(init::ArrayInitializer, inds::Vararg{OffsetAxisKnownLength,N}) where {T,N} = OffsetArray{T,N}(init, inds)
137136
function OffsetArray{T}(init::ArrayInitializer, inds::NTuple{N, Union{OffsetAxisKnownLength, CartesianIndices}}) where {T, N}
138137
# N is probably not the actual dimension of the array; CartesianIndices might contain multiple dimensions
139138
indsN = _expandCartesianIndices(inds)
140139
OffsetArray{T, length(indsN)}(init, indsN)
141140
end
142-
function OffsetArray{T}(init::ArrayInitializer, inds::Vararg{Union{OffsetAxisKnownLength, CartesianIndices}, N}) where {T, N}
143-
OffsetArray{T}(init, inds)
144-
end
145-
function OffsetArray{T}(init::ArrayInitializer, inds::CartesianIndices{N}) where {T,N}
146-
OffsetArray{T, N}(init, convert(Tuple{Vararg{AbstractUnitRange{Int}}}, inds))
147-
end
141+
OffsetArray{T}(init::ArrayInitializer, inds::Union{OffsetAxisKnownLength, CartesianIndices}...) where {T} = OffsetArray{T}(init, inds)
148142

149143
Base.IndexStyle(::Type{OA}) where {OA<:OffsetArray} = IndexStyle(parenttype(OA))
150144
parenttype(::Type{OffsetArray{T,N,AA}}) where {T,N,AA} = AA

test/axes.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
@testset "IdOffsetRange" begin
2+
function same_value(r1, r2)
3+
length(r1) == length(r2) || return false
4+
for (v1, v2) in zip(r1, r2)
5+
v1 == v2 || return false
6+
end
7+
return true
8+
end
9+
function check_indexed_by(r, rindx)
10+
for i in rindx
11+
r[i]
12+
end
13+
@test_throws BoundsError r[minimum(rindx)-1]
14+
@test_throws BoundsError r[maximum(rindx)+1]
15+
return nothing
16+
end
17+
18+
ro = OffsetArrays.IdOffsetRange(Base.OneTo(3))
19+
rs = OffsetArrays.IdOffsetRange(3:5, -2)
20+
@test typeof(ro) !== typeof(rs)
21+
@test same_value(ro, 1:3)
22+
check_indexed_by(ro, 1:3)
23+
@test same_value(rs, 1:3)
24+
check_indexed_by(rs, -1:1)
25+
@test @inferred(typeof(ro)(ro)) === ro
26+
@test @inferred(OffsetArrays.IdOffsetRange{Int}(ro)) === ro
27+
@test @inferred(OffsetArrays.IdOffsetRange{Int16}(ro)) === OffsetArrays.IdOffsetRange(Base.OneTo(Int16(3)))
28+
@test @inferred(OffsetArrays.IdOffsetRange(ro)) === ro
29+
@test parent(ro) === ro.parent
30+
@test parent(rs) === rs.parent
31+
# construction/coercion preserves the values, altering the axes if needed
32+
r2 = @inferred(typeof(rs)(ro))
33+
@test typeof(r2) === typeof(rs)
34+
@test same_value(ro, 1:3)
35+
check_indexed_by(ro, 1:3)
36+
r2 = @inferred(typeof(ro)(rs))
37+
@test typeof(r2) === typeof(ro)
38+
@test same_value(r2, 1:3)
39+
check_indexed_by(r2, 1:3)
40+
# check the example in the comments
41+
r = OffsetArrays.IdOffsetRange{Int,UnitRange{Int}}(3:4)
42+
@test same_value(r, 3:4)
43+
check_indexed_by(r, 1:2)
44+
r = OffsetArrays.IdOffsetRange{Int,Base.OneTo{Int}}(3:4)
45+
@test same_value(r, 3:4)
46+
check_indexed_by(r, 3:4)
47+
r = OffsetArrays.IdOffsetRange{Int,Base.OneTo{Int}}(3:4, -2)
48+
@test same_value(r, 1:2)
49+
check_indexed_by(r, 1:2)
50+
51+
# conversion preserves both the values and the axes, throwing an error if this is not possible
52+
@test @inferred(oftype(ro, ro)) === ro
53+
@test @inferred(convert(OffsetArrays.IdOffsetRange{Int}, ro)) === ro
54+
@test @inferred(convert(OffsetArrays.IdOffsetRange{Int}, rs)) === rs
55+
@test @inferred(convert(OffsetArrays.IdOffsetRange{Int16}, ro)) === OffsetArrays.IdOffsetRange(Base.OneTo(Int16(3)))
56+
r2 = @inferred(oftype(rs, ro))
57+
@test typeof(r2) === typeof(rs)
58+
@test same_value(r2, 1:3)
59+
check_indexed_by(r2, 1:3)
60+
# These two broken tests can be fixed by uncommenting the `convert` definitions
61+
# in axes.jl, but unfortunately Julia may not quite be ready for this. (E.g. `reinterpretarray.jl`)
62+
@test_broken try oftype(ro, rs); false catch err true end # replace with line below
63+
# @test_throws ArgumentError oftype(ro, rs)
64+
@test @inferred(oftype(ro, Base.OneTo(2))) === OffsetArrays.IdOffsetRange(Base.OneTo(2))
65+
@test @inferred(oftype(ro, 1:2)) === OffsetArrays.IdOffsetRange(Base.OneTo(2))
66+
@test_broken try oftype(ro, 3:4); false catch err true end
67+
# @test_throws ArgumentError oftype(ro, 3:4)
68+
69+
# broadcasting behavior with scalars (issue #104)
70+
r3 = (1 .+ OffsetArrays.IdOffsetRange(3:5, -1) .+ 1) .- 1
71+
@test same_value(r3, 3:5)
72+
check_indexed_by(r3, 0:2)
73+
end

0 commit comments

Comments
 (0)