-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Description
The wrap
function, added by @MasonProtter in #52049, seems like it would be generally useful. It's like a converting constructor for arrays, but non-copying. The interface is basically wrap(output_type::Type, vector_to_be_wrapped)
, with optional trailing arguments for the shape also being supported:
Lines 3159 to 3206 in 895a981
""" | |
wrap(Array, m::Union{Memory{T}, MemoryRef{T}}, dims) | |
Create an array of size `dims` using `m` as the underlying memory. This can be thought of as a safe version | |
of [`unsafe_wrap`](@ref) utilizing `Memory` or `MemoryRef` instead of raw pointers. | |
""" | |
function wrap end | |
# validity checking for _wrap calls, separate from allocation of Array so that it can be more likely to inline into the caller | |
function _wrap(ref::MemoryRef{T}, dims::NTuple{N, Int}) where {T, N} | |
mem = ref.mem | |
mem_len = length(mem) + 1 - memoryrefoffset(ref) | |
len = Core.checked_dims(dims...) | |
@boundscheck mem_len >= len || invalid_wrap_err(mem_len, dims, len) | |
return ref | |
end | |
@noinline invalid_wrap_err(len, dims, proddims) = throw(DimensionMismatch(LazyString( | |
"Attempted to wrap a MemoryRef of length ", len, " with an Array of size dims=", dims, | |
" which is invalid because prod(dims) = ", proddims, " > ", len, | |
" so that the array would have more elements than the underlying memory can store."))) | |
@eval @propagate_inbounds function wrap(::Type{Array}, m::MemoryRef{T}, dims::NTuple{N, Integer}) where {T, N} | |
dims = convert(Dims, dims) | |
ref = _wrap(m, dims) | |
$(Expr(:new, :(Array{T, N}), :ref, :dims)) | |
end | |
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}, dims::NTuple{N, Integer}) where {T, N} | |
dims = convert(Dims, dims) | |
ref = _wrap(memoryref(m), dims) | |
$(Expr(:new, :(Array{T, N}), :ref, :dims)) | |
end | |
@eval @propagate_inbounds function wrap(::Type{Array}, m::MemoryRef{T}, l::Integer) where {T} | |
dims = (Int(l),) | |
ref = _wrap(m, dims) | |
$(Expr(:new, :(Array{T, 1}), :ref, :dims)) | |
end | |
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}, l::Integer) where {T} | |
dims = (Int(l),) | |
ref = _wrap(memoryref(m), (l,)) | |
$(Expr(:new, :(Array{T, 1}), :ref, :dims)) | |
end | |
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}) where {T} | |
ref = memoryref(m) | |
dims = (length(m),) | |
$(Expr(:new, :(Array{T, 1}), :ref, :dims)) | |
end |
Some questions that come to mind:
-
What's the generic signature? Something like
wrap(::Type{<:AbstractArray}, ::AbstractVector[, ::Dims])
? What's the most generic way to write the doc string? Can this support things other than arrays? -
What should happen when a non-
AbstractVector
AbstractArray
is passed as the second argument? -
The short and nondescript name makes me uncomfortable. Perhaps something like
wrap_in
orwrap_into
would be better? See also:wrap
is a very generic name to export #53552
Motivation: I think it'd be nice if FixedSizeArrays.jl could add methods to wrap
to support wrapping other array types, cc @giordano @oscardssmith. The method could look like this:
function Base.wrap(::Type{FixedSizeVector}, vec::Union{Vector, Memory})
new_fixed_size_array(vec, length(vec))
end