From 70005014ed216cbf612bfffdcef6b5973af8890d Mon Sep 17 00:00:00 2001 From: nhz2 Date: Mon, 2 Feb 2026 13:29:39 -0500 Subject: [PATCH 1/2] Add generic Base.unsafe_read using has_strided_get --- src/InputBuffers.jl | 73 ++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/src/InputBuffers.jl b/src/InputBuffers.jl index 7035bac..9e3c5a8 100644 --- a/src/InputBuffers.jl +++ b/src/InputBuffers.jl @@ -90,33 +90,52 @@ function Base.readbytes!(b::InputBuffer, out::AbstractArray{UInt8}, nb=length(ou end Base.readavailable(b::InputBuffer) = read(b) -const ByteVector = Union{ - Vector{UInt8}, - Base.CodeUnits{UInt8, String}, - typeof(view(codeunits("abc"), :)), - typeof(view(codeunits("abc"), 1:2)), - typeof(view(zeros(UInt8, 3), :)), - typeof(view(zeros(UInt8, 3), 1:2)) -} - -# Using @noinline to hopefully prevent strange TBAA issues based on where p comes from -@noinline function Base.unsafe_read(b::InputBuffer, p::Ptr{UInt8}, n::UInt)::Nothing - nb::Int64 = min(n, bytesavailable(b)) - temp = Vector{UInt8}(undef, nb) - copyto!(temp, Int64(1), b.data, Int64(b.pos+firstindex(b.data)), nb) - cconv_temp = Base.cconvert(Ptr{UInt8}, temp) - GC.@preserve cconv_temp unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_temp), nb) - b.pos += nb - nb < n && throw(EOFError()) - nothing -end -@noinline function Base.unsafe_read(b::InputBuffer{<:ByteVector}, p::Ptr{UInt8}, n::UInt)::Nothing - nb::Int64 = min(n, bytesavailable(b)) - cconv_data = Base.cconvert(Ptr{UInt8}, b.data) - GC.@preserve cconv_data unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_data) + b.pos, nb) - b.pos += nb - nb < n && throw(EOFError()) - nothing +@static if isdefined(Base, :has_strided_get) + # Using @noinline to hopefully prevent strange TBAA issues based on where p comes from + @noinline function Base.unsafe_read(b::InputBuffer, p::Ptr{UInt8}, n::UInt)::Nothing + nb::Int64 = min(n, bytesavailable(b)) + if has_strided_get(b.data) && isone(Base.elsize(b.data)) && isone(only(strides(b.data))) + cconv_data = Base.cconvert(Ptr{UInt8}, b.data) + GC.@preserve cconv_data unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_data) + b.pos, nb) + else + temp = Vector{UInt8}(undef, nb) + copyto!(temp, Int64(1), b.data, Int64(b.pos+firstindex(b.data)), nb) + cconv_temp = Base.cconvert(Ptr{UInt8}, temp) + GC.@preserve cconv_temp unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_temp), nb) + end + b.pos += nb + nb < n && throw(EOFError()) + nothing + end +else + const ByteVector = Union{ + Vector{UInt8}, + Base.CodeUnits{UInt8, String}, + typeof(view(codeunits("abc"), :)), + typeof(view(codeunits("abc"), 1:2)), + typeof(view(zeros(UInt8, 3), :)), + typeof(view(zeros(UInt8, 3), 1:2)) + } + + # Using @noinline to hopefully prevent strange TBAA issues based on where p comes from + @noinline function Base.unsafe_read(b::InputBuffer, p::Ptr{UInt8}, n::UInt)::Nothing + nb::Int64 = min(n, bytesavailable(b)) + temp = Vector{UInt8}(undef, nb) + copyto!(temp, Int64(1), b.data, Int64(b.pos+firstindex(b.data)), nb) + cconv_temp = Base.cconvert(Ptr{UInt8}, temp) + GC.@preserve cconv_temp unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_temp), nb) + b.pos += nb + nb < n && throw(EOFError()) + nothing + end + @noinline function Base.unsafe_read(b::InputBuffer{<:ByteVector}, p::Ptr{UInt8}, n::UInt)::Nothing + nb::Int64 = min(n, bytesavailable(b)) + cconv_data = Base.cconvert(Ptr{UInt8}, b.data) + GC.@preserve cconv_data unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_data) + b.pos, nb) + b.pos += nb + nb < n && throw(EOFError()) + nothing + end end # TODO Benchmark to see if the following are worth implementing From 0cb911a7317dd41cd6118aa26ccf44f9b2c31de1 Mon Sep 17 00:00:00 2001 From: nhz2 Date: Mon, 18 May 2026 21:39:46 -0400 Subject: [PATCH 2/2] switch to try_strides --- src/InputBuffers.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/InputBuffers.jl b/src/InputBuffers.jl index 9e3c5a8..fd863bb 100644 --- a/src/InputBuffers.jl +++ b/src/InputBuffers.jl @@ -90,11 +90,11 @@ function Base.readbytes!(b::InputBuffer, out::AbstractArray{UInt8}, nb=length(ou end Base.readavailable(b::InputBuffer) = read(b) -@static if isdefined(Base, :has_strided_get) +@static if isdefined(Base, :try_strides) # Using @noinline to hopefully prevent strange TBAA issues based on where p comes from @noinline function Base.unsafe_read(b::InputBuffer, p::Ptr{UInt8}, n::UInt)::Nothing nb::Int64 = min(n, bytesavailable(b)) - if has_strided_get(b.data) && isone(Base.elsize(b.data)) && isone(only(strides(b.data))) + if is_ptr_loadable(b.data) && try_strides(b.data) === (1,) && isone(Base.elsize(b.data)) cconv_data = Base.cconvert(Ptr{UInt8}, b.data) GC.@preserve cconv_data unsafe_copyto!(p, Base.unsafe_convert(Ptr{UInt8}, cconv_data) + b.pos, nb) else