Skip to content

[FR] make the wrap function public #58729

Open
@nsajko

Description

@nsajko

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:

julia/base/array.jl

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 or wrap_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

Metadata

Metadata

Assignees

No one assigned

    Labels

    arrays[a, r, r, a, y, s]featureIndicates new feature / enhancement requests

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions