-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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-
AbstractVectorAbstractArrayis passed as the second argument? -
The short and nondescript name makes me uncomfortable. Perhaps something like
wrap_inorwrap_intowould be better? See also:wrapis 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