Skip to content

Commit 080771a

Browse files
authored
Resolve aliasing problems in getindex (#60)
1 parent 040053c commit 080771a

File tree

3 files changed

+32
-36
lines changed

3 files changed

+32
-36
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "PooledArrays"
22
uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
3-
version = "1.2.0"
3+
version = "1.2.1"
44

55
[deps]
66
DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"

src/PooledArrays.jl

+22-35
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ mutable struct PooledArray{T, R<:Integer, N, RA} <: AbstractArray{T, N}
4242
if length(pool) != length(invpool)
4343
throw(ArgumentError("inconsistent pool and invpool"))
4444
end
45-
# refs mustn't overflow pool
46-
minref, maxref = extrema(rs.a)
47-
# 0 indicates #undef
48-
if length(rs.a) > 0 && (minref < 0 || maxref > length(invpool))
49-
throw(ArgumentError("Reference array points beyond the end of the pool"))
45+
if length(rs.a) > 0
46+
# 0 indicates #undef
47+
# refs mustn't overflow pool
48+
minref, maxref = extrema(rs.a)
49+
if (minref < 0 || maxref > length(invpool))
50+
throw(ArgumentError("Reference array points beyond the end of the pool"))
51+
end
5052
end
5153
pa = new{T,R,N,RA}(rs.a, pool, invpool, refcount)
5254
finalizer(x -> Threads.atomic_sub!(x.refcount, 1), pa)
@@ -444,40 +446,25 @@ Base.convert(::Type{Array}, pa::PooledArray{T, R, N}) where {T, R, N} = convert(
444446

445447
# We need separate functions due to dispatch ambiguities
446448

447-
for T in (PooledArray, SubArray{<:Any, <:Any, <:PooledArray})
448-
@eval Base.@propagate_inbounds function Base.getindex(A::$T, I::Integer...)
449-
idx = DataAPI.refarray(A)[I...]
450-
iszero(idx) && throw(UndefRefError())
451-
return @inbounds DataAPI.refpool(A)[idx]
452-
end
453-
454-
@eval Base.@propagate_inbounds function Base.getindex(A::$T, I::Union{Real, AbstractVector}...)
455-
# make sure we do not increase A.refcount in case creation of newrefs fails
456-
newrefs = DataAPI.refarray(A)[I...]
457-
@assert newrefs isa AbstractArray
458-
Threads.atomic_add!(refcount(A), 1)
459-
return PooledArray(RefArray(newrefs), DataAPI.invrefpool(A), DataAPI.refpool(A), refcount(A))
460-
end
461-
end
462-
463-
if VERSION < v"1.1"
464-
Base.@propagate_inbounds function Base.getindex(A::SubArray{T,D,P,I,true} ,
465-
i::Int) where {I<:Tuple{Union{Base.Slice,
466-
AbstractUnitRange},
467-
Vararg{Any}}, P<:PooledArray, T, D}
468-
idx = DataAPI.refarray(A)[i]
469-
iszero(idx) && throw(UndefRefError())
470-
return @inbounds DataAPI.refpool(A)[idx]
471-
end
472-
end
473-
474-
# Defined to avoid ambiguities with Base
475-
Base.@propagate_inbounds function Base.getindex(A::SubArray{<:Any, N, <:PooledArray}, I::Vararg{Int,N}) where {T,N}
476-
idx = DataAPI.refarray(A)[I...]
449+
Base.@propagate_inbounds function Base.getindex(A::PooledArray, I::Int)
450+
idx = DataAPI.refarray(A)[I]
477451
iszero(idx) && throw(UndefRefError())
478452
return @inbounds DataAPI.refpool(A)[idx]
479453
end
480454

455+
# we handle fast only the case when the first index is an abstract vector
456+
# this is to make sure other indexing synraxes use standard dispatch from Base
457+
# the reason is that creation of DataAPI.refarray(A) is unfortunately slow
458+
Base.@propagate_inbounds function Base.getindex(A::PooledArrOrSub,
459+
I1::AbstractVector,
460+
I2::Union{Real, AbstractVector}...)
461+
# make sure we do not increase A.refcount in case creation of newrefs fails
462+
newrefs = DataAPI.refarray(A)[I1, I2...]
463+
@assert newrefs isa AbstractArray
464+
Threads.atomic_add!(refcount(A), 1)
465+
return PooledArray(RefArray(newrefs), DataAPI.invrefpool(A), DataAPI.refpool(A), refcount(A))
466+
end
467+
481468
Base.@propagate_inbounds function Base.isassigned(pa::PooledArrOrSub, I::Int...)
482469
!iszero(DataAPI.refarray(pa)[I...])
483470
end

test/runtests.jl

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ else
1111
end
1212

1313
@testset "PooledArrays" begin
14+
@test eltype(PooledArray(Int[])) === Int
15+
1416
a = rand(10)
1517
b = rand(10,10)
1618
c = rand(1:10, 1000)
@@ -426,6 +428,13 @@ end
426428
@test pav[1:1, [1, 2]] == [1 2]
427429
@test pav[[1], 1:2] == [1 2]
428430
@test pav[[1], [1, 2]] == [1 2]
431+
432+
pav2 = view(PooledArray([1]), 1)
433+
pa2 = similar(pav2)
434+
pa2[] = 10
435+
436+
@test pav2[] == 1
437+
@test pa2[] == 10
429438
end
430439

431440
@testset "isassigned" begin

0 commit comments

Comments
 (0)