Skip to content

Commit 8d41d25

Browse files
authored
Revert changing wrap on Memory to view and make wrap non-public. (#54927)
Fixes #54768
1 parent f225f84 commit 8d41d25

File tree

6 files changed

+79
-72
lines changed

6 files changed

+79
-72
lines changed

base/array.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,3 +3064,56 @@ intersect(r::AbstractRange, v::AbstractVector) = intersect(v, r)
30643064
_getindex(v, i)
30653065
end
30663066
end
3067+
3068+
"""
3069+
wrap(Array, m::Union{Memory{T}, MemoryRef{T}}, dims)
3070+
3071+
Create an array of size `dims` using `m` as the underlying memory. This can be thought of as a safe version
3072+
of [`unsafe_wrap`](@ref) utilizing `Memory` or `MemoryRef` instead of raw pointers.
3073+
"""
3074+
function wrap end
3075+
3076+
# validity checking for _wrap calls, separate from allocation of Array so that it can be more likely to inline into the caller
3077+
function _wrap(ref::MemoryRef{T}, dims::NTuple{N, Int}) where {T, N}
3078+
mem = ref.mem
3079+
mem_len = length(mem) + 1 - memoryrefoffset(ref)
3080+
len = Core.checked_dims(dims...)
3081+
@boundscheck mem_len >= len || invalid_wrap_err(mem_len, dims, len)
3082+
if N != 1 && !(ref === GenericMemoryRef(mem) && len === mem_len)
3083+
mem = ccall(:jl_genericmemory_slice, Memory{T}, (Any, Ptr{Cvoid}, Int), mem, ref.ptr_or_offset, len)
3084+
ref = memoryref(mem)
3085+
end
3086+
return ref
3087+
end
3088+
3089+
@noinline invalid_wrap_err(len, dims, proddims) = throw(DimensionMismatch(LazyString(
3090+
"Attempted to wrap a MemoryRef of length ", len, " with an Array of size dims=", dims,
3091+
" which is invalid because prod(dims) = ", proddims, " > ", len,
3092+
" so that the array would have more elements than the underlying memory can store.")))
3093+
3094+
@eval @propagate_inbounds function wrap(::Type{Array}, m::MemoryRef{T}, dims::NTuple{N, Integer}) where {T, N}
3095+
dims = convert(Dims, dims)
3096+
ref = _wrap(m, dims)
3097+
$(Expr(:new, :(Array{T, N}), :ref, :dims))
3098+
end
3099+
3100+
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}, dims::NTuple{N, Integer}) where {T, N}
3101+
dims = convert(Dims, dims)
3102+
ref = _wrap(memoryref(m), dims)
3103+
$(Expr(:new, :(Array{T, N}), :ref, :dims))
3104+
end
3105+
@eval @propagate_inbounds function wrap(::Type{Array}, m::MemoryRef{T}, l::Integer) where {T}
3106+
dims = (Int(l),)
3107+
ref = _wrap(m, dims)
3108+
$(Expr(:new, :(Array{T, 1}), :ref, :dims))
3109+
end
3110+
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}, l::Integer) where {T}
3111+
dims = (Int(l),)
3112+
ref = _wrap(memoryref(m), (l,))
3113+
$(Expr(:new, :(Array{T, 1}), :ref, :dims))
3114+
end
3115+
@eval @propagate_inbounds function wrap(::Type{Array}, m::Memory{T}) where {T}
3116+
ref = memoryref(m)
3117+
dims = (length(m),)
3118+
$(Expr(:new, :(Array{T, 1}), :ref, :dims))
3119+
end

base/genericmemory.jl

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -316,31 +316,6 @@ function indcopy(sz::Dims, I::GenericMemory)
316316
dst, src
317317
end
318318

319-
# Wrapping a memory region in an Array
320-
@eval begin # @eval for the Array construction. Block for the docstring.
321-
function reshape(m::GenericMemory{M, T}, dims::Vararg{Int, N}) where {M, T, N}
322-
len = Core.checked_dims(dims...)
323-
length(m) == len || throw(DimensionMismatch("parent has $(length(m)) elements, which is incompatible with size $(dims)"))
324-
ref = memoryref(m)
325-
$(Expr(:new, :(Array{T, N}), :ref, :dims))
326-
end
327-
328-
"""
329-
view(m::GenericMemory{M, T}, inds::Union{UnitRange, OneTo})
330-
331-
Create a vector `v::Vector{T}` backed by the specified indices of `m`. It is only safe to
332-
resize `v` if `m` is subseqently not used.
333-
"""
334-
function view(m::GenericMemory{M, T}, inds::Union{UnitRange, OneTo}) where {M, T}
335-
isempty(inds) && return T[] # needed to allow view(Memory{T}(undef, 0), 2:1)
336-
@boundscheck checkbounds(m, inds)
337-
ref = memoryref(m, first(inds)) # @inbounds would be safe here but does not help performance.
338-
dims = (Int(length(inds)),)
339-
$(Expr(:new, :(Array{T, 1}), :ref, :dims))
340-
end
341-
end
342-
view(m::GenericMemory, inds::Colon) = view(m, eachindex(m))
343-
344319
# get, set(once), modify, swap and replace at index, atomically
345320
function getindex_atomic(mem::GenericMemory, order::Symbol, i::Int)
346321
memref = memoryref(mem, i)

base/iobuffer.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ end
4242

4343
# allocate Vector{UInt8}s for IOBuffer storage that can efficiently become Strings
4444
StringMemory(n::Integer) = unsafe_wrap(Memory{UInt8}, _string_n(n))
45-
StringVector(n::Integer) = view(StringMemory(n), 1:n)::Vector{UInt8}
45+
StringVector(n::Integer) = wrap(Array, StringMemory(n))
4646

4747
# IOBuffers behave like Files. They are typically readable and writable. They are seekable. (They can be appendable).
4848

@@ -466,7 +466,7 @@ function take!(io::IOBuffer)
466466
if nbytes == 0 || io.reinit
467467
data = StringVector(0)
468468
elseif io.writable
469-
data = view(io.data, io.offset+1:nbytes+io.offset)
469+
data = wrap(Array, memoryref(io.data, io.offset + 1), nbytes)
470470
else
471471
data = copyto!(StringVector(nbytes), 1, io.data, io.offset + 1, nbytes)
472472
end
@@ -475,7 +475,7 @@ function take!(io::IOBuffer)
475475
if nbytes == 0
476476
data = StringVector(0)
477477
elseif io.writable
478-
data = view(io.data, io.ptr:io.ptr+nbytes-1)
478+
data = wrap(Array, memoryref(io.data, io.ptr), nbytes)
479479
else
480480
data = read!(io, data)
481481
end
@@ -501,7 +501,11 @@ state. This should only be used internally for performance-critical
501501
It might save an allocation compared to `take!` (if the compiler elides the
502502
Array allocation), as well as omits some checks.
503503
"""
504-
_unsafe_take!(io::IOBuffer) = view(io.data, io.offset+1:io.size)
504+
_unsafe_take!(io::IOBuffer) =
505+
wrap(Array, io.size == io.offset ?
506+
memoryref(Memory{UInt8}()) :
507+
memoryref(io.data, io.offset + 1),
508+
io.size - io.offset)
505509

506510
function write(to::IO, from::GenericIOBuffer)
507511
written::Int = bytesavailable(from)

base/strings/string.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,7 @@ String(s::AbstractString) = print_to_string(s)
115115
@assume_effects :total String(s::Symbol) = unsafe_string(unsafe_convert(Ptr{UInt8}, s))
116116

117117
unsafe_wrap(::Type{Memory{UInt8}}, s::String) = ccall(:jl_string_to_genericmemory, Ref{Memory{UInt8}}, (Any,), s)
118-
function unsafe_wrap(::Type{Vector{UInt8}}, s::String)
119-
mem = unsafe_wrap(Memory{UInt8}, s)
120-
view(mem, eachindex(mem))
121-
end
118+
unsafe_wrap(::Type{Vector{UInt8}}, s::String) = wrap(Array, unsafe_wrap(Memory{UInt8}, s))
122119

123120
Vector{UInt8}(s::CodeUnits{UInt8,String}) = copyto!(Vector{UInt8}(undef, length(s)), s)
124121
Vector{UInt8}(s::String) = Vector{UInt8}(codeunits(s))

test/arrayops.jl

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,42 +3219,23 @@ end
32193219
end
32203220
end
32213221

3222-
@testset "Wrapping Memory into Arrays with view and reshape" begin
3223-
mem::Memory{Int} = Memory{Int}(undef, 10) .= 11:20
3224-
3225-
@test_throws DimensionMismatch reshape(mem, 10, 10)
3226-
@test_throws DimensionMismatch reshape(mem, 5)
3227-
@test_throws BoundsError view(mem, 1:10, 1:10)
3228-
@test_throws BoundsError view(mem, 1:11)
3229-
@test_throws BoundsError view(mem, 3:11)
3230-
@test_throws BoundsError view(mem, 0:4)
3231-
3232-
@test @inferred(view(mem, 1:5))::Vector{Int} == 11:15
3233-
@test @inferred(view(mem, 1:2))::Vector{Int} == 11:12
3234-
@test @inferred(view(mem, 1:10))::Vector{Int} == 11:20
3235-
@test @inferred(view(mem, 3:8))::Vector{Int} == 13:18
3236-
@test @inferred(view(mem, 20:19))::Vector{Int} == []
3237-
@test @inferred(view(mem, -5:-7))::Vector{Int} == []
3238-
@test @inferred(view(mem, :))::Vector{Int} == mem
3239-
@test @inferred(reshape(mem, 5, 2))::Matrix{Int} == reshape(11:20, 5, 2)
3240-
3241-
# 53990
3242-
@test @inferred(view(mem, unsigned(1):10))::Vector{Int} == 11:20
3243-
3244-
empty_mem = Memory{Module}(undef, 0)
3245-
@test_throws BoundsError view(empty_mem, 0:1)
3246-
@test_throws BoundsError view(empty_mem, 1:2)
3247-
@test_throws DimensionMismatch reshape(empty_mem, 1)
3248-
@test_throws DimensionMismatch reshape(empty_mem, 1, 2, 3)
3249-
@test_throws ArgumentError reshape(empty_mem, 2^16, 2^16, 2^16, 2^16)
3250-
3251-
@test @inferred(view(empty_mem, 1:0))::Vector{Module} == []
3252-
@test @inferred(view(empty_mem, 10:3))::Vector{Module} == []
3253-
@test @inferred(view(empty_mem, :))::Vector{Module} == empty_mem
3254-
@test isempty(@inferred(reshape(empty_mem, 0, 7, 1))::Array{Module, 3})
3255-
3256-
offset_inds = OffsetArrays.IdOffsetRange(values=3:6, indices=53:56)
3257-
@test @inferred(view(collect(mem), offset_inds)) == view(mem, offset_inds)
3222+
@testset "Wrapping Memory into Arrays" begin
3223+
mem = Memory{Int}(undef, 10) .= 1
3224+
memref = memoryref(mem)
3225+
@test_throws DimensionMismatch Base.wrap(Array, mem, (10, 10))
3226+
@test Base.wrap(Array, mem, (5,)) == ones(Int, 5)
3227+
@test Base.wrap(Array, mem, 2) == ones(Int, 2)
3228+
@test Base.wrap(Array, memref, 10) == ones(Int, 10)
3229+
@test Base.wrap(Array, memref, (2,2,2)) == ones(Int,2,2,2)
3230+
@test Base.wrap(Array, mem, (5, 2)) == ones(Int, 5, 2)
3231+
3232+
memref2 = memoryref(mem, 3)
3233+
@test Base.wrap(Array, memref2, (5,)) == ones(Int, 5)
3234+
@test Base.wrap(Array, memref2, 2) == ones(Int, 2)
3235+
@test Base.wrap(Array, memref2, (2,2,2)) == ones(Int,2,2,2)
3236+
@test Base.wrap(Array, memref2, (3, 2)) == ones(Int, 3, 2)
3237+
@test_throws DimensionMismatch Base.wrap(Array, memref2, 9)
3238+
@test_throws DimensionMismatch Base.wrap(Array, memref2, 10)
32583239
end
32593240

32603241
@testset "Memory size" begin

test/core.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5532,9 +5532,6 @@ let a = Base.StringVector(2^17)
55325532
@test sizeof(c) == 0
55335533
end
55345534

5535-
# issue #53990 / https://github.com/JuliaLang/julia/pull/53896#discussion_r1555087951
5536-
@test Base.StringVector(UInt64(2)) isa Vector{UInt8}
5537-
55385535
@test_throws ArgumentError eltype(Bottom)
55395536

55405537
# issue #16424, re-evaluating type definitions

0 commit comments

Comments
 (0)