Skip to content

Commit

Permalink
add unsafe_read(io, p::Ptr{UInt8}, nb::UInt) counterpart to unsafe_write
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Jan 25, 2016
1 parent beb436c commit 60946e0
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 101 deletions.
2 changes: 1 addition & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ export
unsafe_copy!,
unsafe_load,
unsafe_pointer_to_objref,
#unsafe_read,
unsafe_read,
unsafe_store!,
unsafe_write,

Expand Down
13 changes: 4 additions & 9 deletions base/filesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,13 @@ function read(f::File, ::Type{UInt8})
return ret % UInt8
end

function read!(f::File, a::Vector{UInt8}, nel=length(a))
function unsafe_read(f::File, p::Ptr{UInt8}, nel::UInt)
check_open(f)
if nel < 0 || nel > length(a)
throw(BoundsError())
end
ret = ccall(:jl_fs_read, Int32, (Int32, Ptr{Void}, Csize_t),
f.handle, a, nel)
if ret < nel
throw(EOFError())
end
f.handle, p, nel)
uv_error("read",ret)
return a
ret == nel || throw(EOFError())
nothing
end

nb_available(f::File) = filesize(f) - position(f)
Expand Down
91 changes: 54 additions & 37 deletions base/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,38 @@ function eof end
read(s::IO, ::Type{UInt8}) = error(typeof(s)," does not support byte I/O")
write(s::IO, x::UInt8) = error(typeof(s)," does not support byte I/O")

"""
unsafe_write(io, ref, nbytes)
Copy nbytes from ref (converted to a pointer) into the IO stream object.
It is recommended that IO subtypes override the exact method signature below
to provide more efficient implementations.
"""
function unsafe_write(s::IO, p::Ptr{UInt8}, n::UInt)
local written::Int = 0
for i=1:n
for i = 1:n
written += write(s, unsafe_load(p, i))
end
return written
end

"""
unsafe_read(io, ref, nbytes)
Copy nbytes from the IO stream object into ref (converted to a pointer).
It is recommended that IO subtypes override the exact method signature below
to provide more efficient implementations.
"""
function unsafe_read(s::IO, p::Ptr{UInt8}, n::UInt)
for i = 1:n
unsafe_store!(p, read(s, UInt8)::UInt8, i)
end
nothing
end


# Generic wrappers around other IO objects
abstract AbstractPipe <: IO
function pipe_reader end
Expand All @@ -45,11 +69,9 @@ buffer_writes(io::AbstractPipe, args...) = buffer_writes(pipe_writer(io), args..
flush(io::AbstractPipe) = flush(pipe_writer(io))

read(io::AbstractPipe, byte::Type{UInt8}) = read(pipe_reader(io), byte)
read!(io::AbstractPipe, bytes::Vector{UInt8}) = read!(pipe_reader(io), bytes)
read{T<:AbstractPipe}(io::T, args...) = read(pipe_reader(io), args...)
read!{T<:AbstractPipe}(io::T, args...) = read!(pipe_reader(io), args...)
readuntil{T<:AbstractPipe}(io::T, args...) = readuntil(pipe_reader(io), args...)
unsafe_read(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_read(pipe_reader(io), p, nb)
read(io::AbstractPipe) = read(pipe_reader(io))
readuntil{T<:AbstractPipe}(io::T, args...) = readuntil(pipe_reader(io), args...)
readavailable(io::AbstractPipe) = readavailable(pipe_reader(io))

isreadable(io::AbstractPipe) = isreadable(pipe_reader(io))
Expand Down Expand Up @@ -107,11 +129,11 @@ function write(io::IO, xs...)
return written
end

unsafe_write{T}(s::IO, p::Ref{T}, n::Integer) = unsafe_write(s, unsafe_convert(Ref{T}, p)::Ptr, n)
@noinline unsafe_write{T}(s::IO, p::Ref{T}, n::Integer) = unsafe_write(s, unsafe_convert(Ref{T}, p)::Ptr, n) # mark noinline to ensure ref is gc-rooted somewhere (by the caller)
unsafe_write(s::IO, p::Ptr, n::Integer) = unsafe_write(s, convert(Ptr{UInt8}, p), convert(UInt, n))
write(s::IO, x::Ref) = unsafe_write(s, x, sizeof(eltype(x)))

function write(s::IO, x::Union{Int8,Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128,Float16,Float32,Float64})
write{T}(s::IO, x::Ref{T}) = unsafe_write(s, x, Core.sizeof(T))
write(s::IO, x::Int8) = write(s, reinterpret(UInt8, x))
function write(s::IO, x::Union{Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128,Float16,Float32,Float64})
return write(s, Ref(x))
end

Expand All @@ -126,16 +148,20 @@ function write(s::IO, a::AbstractArray)
return nb
end

function write{T}(s::IO, a::Array{T})
@noinline function write(s::IO, a::Array{UInt8}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
return unsafe_write(s, pointer(a), sizeof(a))
end

@noinline function write{T}(s::IO, a::Array{T}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
if isbits(T)
return unsafe_write(s, pointer(a), sizeof(a))
else
nb = 0
for i in eachindex(a)
nb += write(s, a[i])
end
return nb
end

nb = 0
for x in a
nb += write(s, x)
end
return nb
end


Expand Down Expand Up @@ -171,41 +197,32 @@ function write(to::IO, from::IO)
end
end

@noinline unsafe_read{T}(s::IO, p::Ref{T}, n::Integer) = unsafe_read(s, unsafe_convert(Ref{T}, p)::Ptr, n) # mark noinline to ensure ref is gc-rooted somewhere (by the caller)
unsafe_read(s::IO, p::Ptr, n::Integer) = unsafe_read(s, convert(Ptr{UInt8}, p), convert(UInt, n))
read{T}(s::IO, x::Ref{T}) = (unsafe_read(s, x, Core.sizeof(T)); x)

read(s::IO, ::Type{Int8}) = reinterpret(Int8, read(s,UInt8))

function read{T <: Union{Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128}}(s::IO, ::Type{T})
x = zero(T)
for n = 1:sizeof(x)
x |= (convert(T,read(s,UInt8))<<((n-1)<<3))
end
return x
read(s::IO, ::Type{Int8}) = reinterpret(Int8, read(s, UInt8))
function read(s::IO, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64},Type{Int128},Type{UInt128},Type{Float16},Type{Float32},Type{Float64}})
return read(s, Ref{T}(0))[]::T
end

read(s::IO, ::Type{Bool}) = (read(s,UInt8)!=0)
read(s::IO, ::Type{Float16}) = box(Float16,unbox(Int16,read(s,Int16)))
read(s::IO, ::Type{Float32}) = box(Float32,unbox(Int32,read(s,Int32)))
read(s::IO, ::Type{Float64}) = box(Float64,unbox(Int64,read(s,Int64)))

read{T}(s::IO, ::Type{Ptr{T}}) = convert(Ptr{T}, read(s,UInt))
read{T}(s::IO, ::Type{Ptr{T}}) = convert(Ptr{T}, read(s, UInt))

read{T}(s::IO, t::Type{T}, d1::Int, dims::Int...) = read(s, t, tuple(d1,dims...))
read{T}(s::IO, t::Type{T}, d1::Integer, dims::Integer...) =
read(s, t, convert(Tuple{Vararg{Int}},tuple(d1,dims...)))

read{T}(s::IO, ::Type{T}, dims::Dims) = read!(s, Array(T, dims))

function read!(s::IO, a::Vector{UInt8})
for i in 1:length(a)
a[i] = read(s, UInt8)
end
@noinline function read!(s::IO, a::Array{UInt8}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
unsafe_read(s, pointer(a), sizeof(a))
return a
end

function read!{T}(s::IO, a::Array{T})
@noinline function read!{T}(s::IO, a::Array{T}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller)
if isbits(T)
nb::Int = length(a) * sizeof(T)
read!(s, reinterpret(UInt8, a, (nb,)))
unsafe_read(s, pointer(a), sizeof(a))
else
for i in eachindex(a)
a[i] = read(s, T)
Expand Down Expand Up @@ -324,7 +341,7 @@ function read(s::IO, nb=typemax(Int))
# instead of taking of risk of over-allocating
b = Array(UInt8, nb == typemax(Int) ? 1024 : nb)
nr = readbytes!(s, b, nb)
resize!(b, nr)
return resize!(b, nr)
end

function readstring(s::IO)
Expand Down
34 changes: 17 additions & 17 deletions base/iobuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function copy(b::AbstractIOBuffer)
b.readable, b.writable, b.seekable, b.append, b.maxsize)
ret.size = b.size
ret.ptr = b.ptr
ret
return ret
end

show(io::IO, b::AbstractIOBuffer) = print(io, "IOBuffer(data=UInt8[...], ",
Expand All @@ -52,27 +52,26 @@ show(io::IO, b::AbstractIOBuffer) = print(io, "IOBuffer(data=UInt8[...], ",
"ptr=", b.ptr, ", ",
"mark=", b.mark, ")")

read!(from::AbstractIOBuffer, a::Vector{UInt8}) = read_sub(from, a, 1, length(a))
read!(from::AbstractIOBuffer, a::Array) = read_sub(from, a, 1, length(a))
function unsafe_read(from::AbstractIOBuffer, p::Ptr{UInt8}, nb::UInt)
from.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
avail = nb_available(from)
adv = min(avail, nb)
unsafe_copy!(p, pointer(from.data, from.ptr), adv)
from.ptr += adv
if nb > avail
throw(EOFError())
end
nothing
end

function read_sub{T}(from::AbstractIOBuffer, a::AbstractArray{T}, offs, nel)
from.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
if offs+nel-1 > length(a) || offs < 1 || nel < 0
throw(BoundsError())
end
if isbits(T) && isa(a,Array)
nb = nel * sizeof(T)
avail = nb_available(from)
adv = min(avail, nb)
copy!(pointer_to_array(convert(Ptr{UInt8},pointer(a)), sizeof(a)), # reinterpret(UInt8,a) but without setting the shared data property on a
1 + (1 - offs) * sizeof(T),
from.data,
from.ptr,
adv)
from.ptr += adv
if nb > avail
throw(EOFError())
end
nb = UInt(nel * sizeof(T))
unsafe_read(from, pointer(a, offs), nb)
else
for i = offs:offs+nel-1
a[i] = read(to, T)
Expand All @@ -82,9 +81,9 @@ function read_sub{T}(from::AbstractIOBuffer, a::AbstractArray{T}, offs, nel)
end

@inline function read(from::AbstractIOBuffer, ::Type{UInt8})
from.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
ptr = from.ptr
size = from.size
from.readable || throw(ArgumentError("read failed, IOBuffer is not readable"))
if ptr > size
throw(EOFError())
end
Expand Down Expand Up @@ -323,7 +322,8 @@ end
return sizeof(UInt8)
end

function readbytes!(io::AbstractIOBuffer, b::Array{UInt8}, nb=length(b))
readbytes!(io::AbstractIOBuffer, b::Array{UInt8}, nb=length(b)) = readbytes!(io, b, Int(nb))
function readbytes!(io::AbstractIOBuffer, b::Array{UInt8}, nb::Int)
nr = min(nb, nb_available(io))
if length(b) < nr
resize!(b, nr)
Expand Down
16 changes: 9 additions & 7 deletions base/iostream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function unsafe_write(s::IOStream, p::Ptr{UInt8}, nb::UInt)
if !iswritable(s)
throw(ArgumentError("write failed, IOStream is not writeable"))
end
Int(ccall(:ios_write, Csize_t, (Ptr{Void}, Ptr{Void}, Csize_t), s.ios, p, nb))
return Int(ccall(:ios_write, Csize_t, (Ptr{Void}, Ptr{Void}, Csize_t), s.ios, p, nb))
end

function write{T,N,A<:Array}(s::IOStream, a::SubArray{T,N,A})
Expand Down Expand Up @@ -153,19 +153,21 @@ function read(s::IOStream, ::Type{UInt8})
if b == -1
throw(EOFError())
end
b % UInt8
return b % UInt8
end

function read{T<:Union{UInt16, Int16, UInt32, Int32, UInt64, Int64}}(s::IOStream, ::Type{T})
ccall(:jl_ios_get_nbyte_int, UInt64, (Ptr{Void}, Csize_t), s.ios, sizeof(T)) % T
if ENDIAN_BOM == 0x04030201
function read(s::IOStream, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64}})
return ccall(:jl_ios_get_nbyte_int, UInt64, (Ptr{Void}, Csize_t), s.ios, sizeof(T)) % T
end
end

function read!(s::IOStream, a::Vector{UInt8})
function unsafe_read(s::IOStream, p::Ptr{UInt8}, nb::UInt)
if ccall(:ios_readall, Csize_t,
(Ptr{Void}, Ptr{Void}, Csize_t), s.ios, a, sizeof(a)) < sizeof(a)
(Ptr{Void}, Ptr{Void}, Csize_t), s, p, nb) != nb
throw(EOFError())
end
a
nothing
end

## text I/O ##
Expand Down
Loading

0 comments on commit 60946e0

Please sign in to comment.