diff --git a/NEWS.md b/NEWS.md index fd68ecce6d5ed..ee9345f0e077b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -581,6 +581,9 @@ Library improvements like other `AbstractDict` subtypes and its constructors mirror the ones of `Dict`. ([#25210]) + * `IOBuffer` can take the `sizehint` keyword argument to suggest a capacity of + the buffer ([#25944]). + Compiler/Runtime improvements ----------------------------- diff --git a/base/iobuffer.jl b/base/iobuffer.jl index 422092f9ccd18..b19b9b3a782bd 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -40,6 +40,7 @@ It may take optional keyword arguments: - `read`, `write`, `append`: restricts operations to the buffer; see `open` for details. - `truncate`: truncates the buffer size to zero length. - `maxsize`: specifies a size beyond which the buffer may not be grown. +- `sizehint`: suggests a capacity of the buffer (`data` must implement `sizehint!(data, size)`). When `data` is not given, the buffer will be both readable and writable by default. @@ -84,10 +85,14 @@ function IOBuffer( write::Union{Bool,Nothing}=nothing, append::Union{Bool,Nothing}=nothing, truncate::Union{Bool,Nothing}=nothing, - maxsize::Integer=typemax(Int)) + maxsize::Integer=typemax(Int), + sizehint::Union{Integer,Nothing}=nothing) if maxsize < 0 throw(ArgumentError("negative maxsize: $(maxsize)")) end + if sizehint !== nothing + sizehint!(data, sizehint) + end flags = open_flags(read=read, write=write, append=append, truncate=truncate) buf = GenericIOBuffer(data, flags.read, flags.write, true, flags.append, Int(maxsize)) if flags.truncate @@ -101,8 +106,9 @@ function IOBuffer(; write::Union{Bool,Nothing}=true, append::Union{Bool,Nothing}=nothing, truncate::Union{Bool,Nothing}=true, - maxsize::Integer=typemax(Int)) - size = maxsize == typemax(Int) ? 32 : Int(maxsize) + maxsize::Integer=typemax(Int), + sizehint::Union{Integer,Nothing}=nothing) + size = sizehint !== nothing ? Int(sizehint) : maxsize != typemax(Int) ? Int(maxsize) : 32 flags = open_flags(read=read, write=write, append=append, truncate=truncate) buf = IOBuffer( StringVector(size), diff --git a/base/strings/basic.jl b/base/strings/basic.jl index a747ac39e5b8e..6e83d9f263f4b 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -512,8 +512,7 @@ isascii(s::AbstractString) = all(isascii, s) ## string map, filter, has ## function map(f, s::AbstractString) - out = IOBuffer(StringVector(sizeof(s)), read=true, write=true) - truncate(out, 0) + out = IOBuffer(sizehint=sizeof(s)) for c in s c′ = f(c) isa(c′, Char) || throw(ArgumentError( @@ -525,8 +524,7 @@ function map(f, s::AbstractString) end function filter(f, s::AbstractString) - out = IOBuffer(StringVector(sizeof(s)), read=true, write=true) - truncate(out, 0) + out = IOBuffer(sizehint=sizeof(s)) for c in s f(c) && write(out, c) end diff --git a/base/strings/io.jl b/base/strings/io.jl index 97dbf4eed89e6..86009bd456e27 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -81,10 +81,7 @@ julia> sprint(showcompact, 66.66666) ``` """ function sprint(f::Function, args...; context=nothing, sizehint::Integer=0) - s = IOBuffer(StringVector(sizehint), read=true, write=true) - # specialized version of truncate(s,0) - s.size = 0 - s.ptr = 1 + s = IOBuffer(sizehint=sizehint) if context !== nothing f(IOContext(s, context), args...) else @@ -99,11 +96,11 @@ tostr_sizehint(x::Float64) = 20 tostr_sizehint(x::Float32) = 12 function print_to_string(xs...; env=nothing) + if isempty(xs) + return "" + end # specialized for performance reasons - s = IOBuffer(StringVector(tostr_sizehint(xs[1])), read=true, write=true) - # specialized version of truncate(s,0) - s.size = 0 - s.ptr = 1 + s = IOBuffer(sizehint=tostr_sizehint(xs[1])) if env !== nothing env_io = IOContext(s, env) for x in xs @@ -436,8 +433,7 @@ Returns: function unindent(str::AbstractString, indent::Int; tabwidth=8) indent == 0 && return str # Note: this loses the type of the original string - buf = IOBuffer(StringVector(sizeof(str)), read=true, write=true) - truncate(buf,0) + buf = IOBuffer(sizehint=sizeof(str)) cutting = true col = 0 # current column (0 based) for ch in str diff --git a/base/strings/util.jl b/base/strings/util.jl index 9fe05fe6edcf5..9d6839665d053 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -383,9 +383,7 @@ function replace(str::String, pat_repl::Pair; count::Integer=typemax(Int)) i = a = firstindex(str) r = coalesce(findnext(pattern,str,i), 0) j, k = first(r), last(r) - out = IOBuffer(StringVector(floor(Int, 1.2sizeof(str))), read=true, write=true) - out.size = 0 - out.ptr = 1 + out = IOBuffer(sizehint=floor(Int, 1.2sizeof(str))) while j != 0 if i == a || i <= k unsafe_write(out, pointer(str, i), UInt(j-i))