Skip to content

Commit 57269e8

Browse files
committed
Inline support for isbits union array element types
1 parent 66e6946 commit 57269e8

File tree

8 files changed

+300
-104
lines changed

8 files changed

+300
-104
lines changed

base/array.jl

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,36 @@ size(a::Array{<:Any,N}) where {N} = (@_inline_meta; ntuple(M -> size(a, M), Val(
9898

9999
asize_from(a::Array, n) = n > ndims(a) ? () : (arraysize(a,n), asize_from(a, n+1)...)
100100

101+
"""
102+
Base.isbitsunion(::Type{T})
103+
104+
Return whether a type is an "is-bits" Union type, meaning each type included in a Union is `isbits`.
105+
"""
106+
function isbitsunion end
107+
108+
function isbitsunion(U::Union)
109+
for u in Base.uniontypes(U)
110+
isbits(u) || return false
111+
end
112+
return true
113+
end
114+
isbitsunion(T) = false
115+
116+
"""
117+
Base.bitsunionsize(U::Union)
118+
119+
For a Union of `isbits` types, return the size of the largest type.
120+
"""
121+
function bitsunionsize(U::Union)
122+
sz = 0
123+
for u in Base.uniontypes(U)
124+
sz = max(sz, sizeof(u))
125+
end
126+
return sz
127+
end
128+
101129
length(a::Array) = arraylen(a)
102-
elsize(a::Array{T}) where {T} = isbits(T) ? sizeof(T) : sizeof(Ptr)
130+
elsize(a::Array{T}) where {T} = isbits(T) ? sizeof(T) : (isbitsunion(T) ? bitsunionsize(T) : sizeof(Ptr))
103131
sizeof(a::Array) = Core.sizeof(a)
104132

105133
function isassigned(a::Array, i::Int...)
@@ -109,6 +137,19 @@ function isassigned(a::Array, i::Int...)
109137
ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii) == 1
110138
end
111139

140+
"""
141+
Base.selectorbytes(A::Array{T, N}) -> Array{UInt8, N}
142+
143+
For an Array with `isbits` Union elements, return the "selector bytes" that indicate the index
144+
of the type for each array element, i.e. the type of `A[1]` is `Base.uniontypes(eltype(A))[Base.selectorbytes(A)[1] + 1]`.
145+
**NOTE**: The actual array selector bytes are returned, meaning if individual elements are modified, the original array will reflect those changes.
146+
Setting selector bytes to invalid or out-of-bounds type indexes may corrupt the original array.
147+
"""
148+
function selectorbytes(a::Array{T, N}) where {T, N}
149+
isbitsunion(T) || return UInt8[]
150+
return unsafe_wrap(Array{UInt8, N}, convert(Ptr{UInt8}, pointer(a)) + length(a) * elsize(a), size(a))
151+
end
152+
112153
## copy ##
113154

114155
function unsafe_copy!(dest::Ptr{T}, src::Ptr{T}, n) where T
@@ -143,7 +184,7 @@ copy!(dest::Array{T}, src::Array{T}) where {T} = copy!(dest, 1, src, 1, length(s
143184
copy(a::T) where {T<:Array} = ccall(:jl_array_copy, Ref{T}, (Any,), a)
144185

145186
function reinterpret(::Type{T}, a::Array{S,1}) where T where S
146-
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
187+
nel = Int(div(length(a) * sizeof(S), sizeof(T)))
147188
# TODO: maybe check that remainder is zero?
148189
return reinterpret(T, a, (nel,))
149190
end
@@ -162,7 +203,7 @@ function reinterpret(::Type{T}, a::Array{S}, dims::NTuple{N,Int}) where T where
162203
end
163204
isbits(T) || throwbits(S, T, T)
164205
isbits(S) || throwbits(S, T, S)
165-
nel = div(length(a)*sizeof(S),sizeof(T))
206+
nel = div(length(a) * sizeof(S), sizeof(T))
166207
if prod(dims) != nel
167208
_throw_dmrsa(dims, nel)
168209
end

0 commit comments

Comments
 (0)