diff --git a/NEWS.md b/NEWS.md index b25a894047526..c9724107d7ee3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -221,6 +221,9 @@ Deprecated or removed * The function `showall` is deprecated. Showing entire values is the default, unless an `IOContext` specifying `:limit=>true` is in use ([#22847]). + * Calling `write` on non-isbits arrays is deprecated in favor of explicit loops or + `serialize` ([#6466]). + Julia v0.6.0 Release Notes ========================== diff --git a/base/deprecated.jl b/base/deprecated.jl index 6d6cb80788759..dd019b7c9faa6 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1591,6 +1591,9 @@ end @deprecate readstring(filename::AbstractString) read(filename, String) @deprecate readstring(cmd::AbstractCmd) read(cmd, String) +# issue #6466 +# `write` on non-isbits arrays is deprecated in io.jl. + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/io.jl b/base/io.jl index e724a38e9649e..6af638cc97a76 100644 --- a/base/io.jl +++ b/base/io.jl @@ -314,6 +314,9 @@ write(s::IO, x::Bool) = write(s, UInt8(x)) write(to::IO, p::Ptr) = write(to, convert(UInt, p)) function write(s::IO, A::AbstractArray) + if !isbits(eltype(A)) + depwarn("Calling `write` on non-isbits arrays is deprecated. Use a loop or `serialize` instead.", :write) + end nb = 0 for a in A nb += write(s, a) @@ -321,14 +324,11 @@ function write(s::IO, A::AbstractArray) return nb end -@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(s::IO, a::Array{T}) where T # mark noinline to ensure the array is gc-rooted somewhere (by the caller) - if isbits(T) +@noinline function write(s::IO, a::Array) # mark noinline to ensure the array is gc-rooted somewhere (by the caller) + if isbits(eltype(a)) return unsafe_write(s, pointer(a), sizeof(a)) else + depwarn("Calling `write` on non-isbits arrays is deprecated. Use a loop or `serialize` instead.", :write) nb = 0 for b in a nb += write(s, b) @@ -337,6 +337,27 @@ end end end +function write(s::IO, a::SubArray{T,N,<:Array}) where {T,N} + if !isbits(T) + return invoke(write, Tuple{IO, AbstractArray}, s, a) + end + elsz = sizeof(T) + colsz = size(a,1) * elsz + if stride(a,1) != 1 + for idxs in CartesianRange(size(a)) + unsafe_write(s, pointer(a, idxs.I), elsz) + end + return elsz * length(a) + elseif N <= 1 + return unsafe_write(s, pointer(a, 1), colsz) + else + for idxs in CartesianRange((1, size(a)[2:end]...)) + unsafe_write(s, pointer(a, idxs.I), colsz) + end + return colsz * trailingsize(a,2) + end +end + function write(s::IO, ch::Char) c = reinterpret(UInt32, ch) diff --git a/base/iostream.jl b/base/iostream.jl index c802c94b87ff7..3ee3c315d36c3 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -169,21 +169,6 @@ function unsafe_write(s::IOStream, p::Ptr{UInt8}, nb::UInt) return Int(ccall(:ios_write, Csize_t, (Ptr{Void}, Ptr{Void}, Csize_t), s.ios, p, nb)) end -function write(s::IOStream, a::SubArray{T,N,<:Array}) where {T,N} - if !isbits(T) || stride(a,1)!=1 - return invoke(write, Tuple{Any, AbstractArray}, s, a) - end - colsz = size(a,1)*sizeof(T) - if N<=1 - return unsafe_write(s, pointer(a, 1), colsz) - else - for idxs in CartesianRange((1, size(a)[2:end]...)) - unsafe_write(s, pointer(a, idxs.I), colsz) - end - return colsz*trailingsize(a,2) - end -end - # num bytes available without blocking nb_available(s::IOStream) = ccall(:jl_nb_available, Int32, (Ptr{Void},), s.ios) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 2f2dff88546a1..5c0a72c35aac8 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -69,11 +69,13 @@ end @test_throws ArgumentError gensym("ab\0") # issue #6949 -let f =IOBuffer(), +let f = IOBuffer(), x = split("1 2 3") - @test write(f, x) == 3 - @test String(take!(f)) == "123" - @test invoke(write, Tuple{IO, AbstractArray}, f, x) == 3 + local nb = 0 + for c in x + nb += write(f, c) + end + @test nb == 3 @test String(take!(f)) == "123" end