Skip to content

Commit f0dbc65

Browse files
authored
fix checked_dims (#44)
xref JuliaLang/julia#54244 Fixes #40
1 parent 6975d6d commit f0dbc65

File tree

2 files changed

+33
-14
lines changed

2 files changed

+33
-14
lines changed

src/FixedSizeArrays.jl

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,32 @@ Base.isassigned(a::FixedSizeArray, i::Int) = isassigned(a.mem, i)
4747

4848
# safe product of a tuple of integers, for calculating dimensions size
4949

50-
checked_dims_impl(a::Int, ::Tuple{}) = a
51-
function checked_dims_impl(a::Int, t::Tuple{Int,Vararg{Int,N}}) where {N}
50+
checked_dims_impl(a::Int, ::Tuple{}, have_overflow::Bool) = (a, have_overflow)
51+
function checked_dims_impl(a::Int, t::Tuple{Int,Vararg{Int,N}}, have_overflow::Bool) where {N}
5252
b = first(t)
53-
tmax = typemax(a)
54-
if (a == tmax) || (b == tmax)
55-
throw(ArgumentError("array dimension size can't be the maximum representable value"))
56-
end
57-
if (a < 0) || (b < 0)
58-
throw(ArgumentError("array dimension size can't be negative"))
59-
end
6053
(m, o) = Base.Checked.mul_with_overflow(a, b)
61-
if o
62-
throw(ArgumentError("array dimensions too great, can't represent length"))
63-
end
6454
r = Base.tail(t)::NTuple{N,Int}
65-
checked_dims_impl(m, r)::Int
55+
checked_dims_impl(m, r, have_overflow | o)::Tuple{Int,Bool}
6656
end
6757

6858
checked_dims(::Tuple{}) = 1
6959
function checked_dims(t::Tuple{Int,Vararg{Int,N}}) where {N}
60+
any_is_zero = any(iszero, t)::Bool
61+
any_is_negative = any((x -> x < false), t)::Bool
62+
any_is_typemax = any((x -> x == typemax(x)), t)::Bool
7063
a = first(t)
7164
r = Base.tail(t)::NTuple{N,Int}
72-
checked_dims_impl(a, r)::Int
65+
(product, have_overflow) = checked_dims_impl(a, r, false)::Tuple{Int,Bool}
66+
if any_is_negative
67+
throw(ArgumentError("array dimension size can't be negative"))
68+
end
69+
if any_is_typemax
70+
throw(ArgumentError("array dimension size can't be the maximum representable value"))
71+
end
72+
if have_overflow & !any_is_zero
73+
throw(ArgumentError("array dimensions too great, can't represent length"))
74+
end
75+
product
7376
end
7477

7578
# broadcasting

test/runtests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@ end
6060
@test_throws DimensionMismatch FixedSizeArray{Int}(oa)
6161
@test_throws DimensionMismatch FixedSizeVector{Int}(oa)
6262
end
63+
@testset "taken from Julia's test/core.jl" begin
64+
# inspired by:
65+
# https://github.com/JuliaLang/julia/blob/83929ad883c97fa4376618c4559b74f6ada7a3ce/test/core.jl#L7211-L7228
66+
b = prevpow(2, typemax(Int))
67+
test_inferred(FixedSizeArray{Int}, FixedSizeArray{Int,3}, (undef, 0, b, b))
68+
test_inferred(FixedSizeArray{Int}, FixedSizeArray{Int,3}, (undef, b, b, 0))
69+
test_inferred(FixedSizeArray{Int}, FixedSizeArray{Int,5}, (undef, b, b, 0, b, b))
70+
@test_throws ArgumentError FixedSizeArray{Int}(undef, b, b)
71+
@test_throws ArgumentError FixedSizeArray{Int}(undef, 1, b, b)
72+
@test_throws ArgumentError FixedSizeArray{Int}(undef, 0, -10)
73+
@test_throws ArgumentError FixedSizeArray{Int}(undef, -10, 0)
74+
@test_throws ArgumentError FixedSizeArray{Int}(undef, -1, -1)
75+
@test_throws ArgumentError FixedSizeArray{Int}(undef, 0, -4, -4)
76+
@test_throws ArgumentError FixedSizeArray{Int}(undef, -4, 1, 0)
77+
@test_throws ArgumentError FixedSizeArray{Int}(undef, -4, -4, 1)
78+
end
6379
@test_throws ArgumentError FixedSizeArray{Float64,1}(undef, -1)
6480
@test_throws ArgumentError FixedSizeArray{Float64,1}(undef, (-1,))
6581
@test_throws ArgumentError FixedSizeArray{Float64,2}(undef, -1, -1)

0 commit comments

Comments
 (0)