Skip to content

Commit

Permalink
improve performance for string(...) (#28876)
Browse files Browse the repository at this point in the history
* improve performance for various string methods

(cherry picked from commit 7314249)
  • Loading branch information
KristofferC committed Sep 8, 2018
1 parent e68ec1e commit 54bafc1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 22 deletions.
38 changes: 25 additions & 13 deletions base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,31 +103,43 @@ function sprint(f::Function, args...; context=nothing, sizehint::Integer=0)
String(resize!(s.data, s.size))
end

tostr_sizehint(x) = 0
tostr_sizehint(x) = 8
tostr_sizehint(x::AbstractString) = lastindex(x)
tostr_sizehint(x::Float64) = 20
tostr_sizehint(x::Float32) = 12

function print_to_string(xs...; env=nothing)
function print_to_string(xs...)
if isempty(xs)
return ""
end
siz = 0
for x in xs
siz += tostr_sizehint(x)
end
# specialized for performance reasons
s = IOBuffer(sizehint=tostr_sizehint(xs[1]))
if env !== nothing
env_io = IOContext(s, env)
for x in xs
print(env_io, x)
end
else
for x in xs
print(s, x)
end
s = IOBuffer(sizehint=siz)
for x in xs
print(s, x)
end
String(resize!(s.data, s.size))
end

string_with_env(env, xs...) = print_to_string(xs...; env=env)
function string_with_env(env, xs...)
if isempty(xs)
return ""
end
siz = 0
for x in xs
siz += tostr_sizehint(x)
end
# specialized for performance reasons
s = IOBuffer(sizehint=siz)
env_io = IOContext(s, env)
for x in xs
print(env_io, x)
end
String(resize!(s.data, s.size))
end

"""
string(xs...)
Expand Down
31 changes: 22 additions & 9 deletions base/strings/substring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,32 @@ function reverse(s::Union{String,SubString{String}})::String
end
end

function string(a::Union{String, SubString{String}}...)
if length(a) == 1
return String(a[1])
end
string(a::String) = String(a)
string(a::SubString{String}) = String(a)

function string(a::Union{Char, String, SubString{String}}...)
n = 0
for str in a
n += sizeof(str)
for v in a
if v isa Char
n += codelen(v)
else
n += sizeof(v)
end
end
out = _string_n(n)
offs = 1
for str in a
unsafe_copyto!(pointer(out,offs), pointer(str), sizeof(str))
offs += sizeof(str)
for v in a
if v isa Char
x = bswap(reinterpret(UInt32, v))
for j in 1:codelen(v)
unsafe_store!(pointer(out, offs), x % UInt8)
offs += 1
x >>= 8
end
else
unsafe_copyto!(pointer(out,offs), pointer(v), sizeof(v))
offs += sizeof(v)
end
end
return out
end
Expand Down
1 change: 1 addition & 0 deletions test/strings/basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ using Random
@test string("∀∃", "1∀∃") === "∀∃1∀∃"
@test string(SubString("∀∃"), SubString("1∀∃", 2)) === "∀∃∀∃"
@test string(s"123") === s"123"
@test string("123", 'α', SubString("1∀∃", 2), 'a', "foo") === "123α∀∃afoo"
codegen_egal_of_strings(x, y) = (x===y, x!==y)
@test codegen_egal_of_strings(string("ab", 'c'), "abc") === (true, false)
let strs = ["", "a", "a b c", "до свидания"]
Expand Down

0 comments on commit 54bafc1

Please sign in to comment.