Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show(io::IO, int) optimization #41415

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ include("io.jl")
include("iobuffer.jl")

# strings & printing
include("scratch_buffer.jl")
include("intfuncs.jl")
include("strings/strings.jl")
include("regex.jl")
Expand Down Expand Up @@ -492,6 +493,7 @@ function __init__()
# Base library init
reinit_stdio()
Multimedia.reinit_displays() # since Multimedia.displays uses stdout as fallback
init_scratch_buffers()
# initialize loading
init_depot_path()
init_load_path()
Expand Down
175 changes: 150 additions & 25 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -657,10 +657,7 @@ ndigits(x::Integer; base::Integer=10, pad::Integer=1) = max(pad, ndigits0z(x, ba

## integer to string functions ##

function bin(x::Unsigned, pad::Int, neg::Bool)
m = 8 * sizeof(x) - leading_zeros(x)
n = neg + max(pad, m)
a = StringVector(n)
@inline function bin_impl_(a, x::Unsigned, n::Int, neg::Bool)
# for i in 0x0:UInt(n-1) # automatic vectorization produces redundant codes
# @inbounds a[n - i] = 0x30 + (((x >> i) % UInt8)::UInt8 & 0x1)
# end
Expand All @@ -681,29 +678,67 @@ function bin(x::Unsigned, pad::Int, neg::Bool)
i -= 1
end
if neg; @inbounds a[1]=0x2d; end
String(a)

nothing
end

function oct(x::Unsigned, pad::Int, neg::Bool)
m = div(8 * sizeof(x) - leading_zeros(x) + 2, 3)
function bin(x::Unsigned, pad::Int, neg::Bool)
m = 8 * sizeof(x) - Base.leading_zeros(x)
n = neg + max(pad, m)
a = StringVector(n)


with_scratch_buffer(n) do a
bin_impl_(a, x, n, neg)
String(a)
end
end

function bin_io(io::IO, x::Unsigned, pad::Int, neg::Bool)
m = 8 * sizeof(x) - Base.leading_zeros(x)
n = neg + max(pad, m)

with_scratch_buffer(n) do scratch
bin_impl_(scratch, x, n, neg)
write(io, scratch)
end
end

@inline function oct_impl_(a, x::Unsigned, n::Int, neg::Bool)
i = n
while i > neg
@inbounds a[i] = 0x30 + ((x % UInt8)::UInt8 & 0x7)
x >>= 0x3
i -= 1
end
if neg; @inbounds a[1]=0x2d; end
String(a)

nothing
end

function oct(x::Unsigned, pad::Int, neg::Bool)
m = div(8 * sizeof(x) - Base.leading_zeros(x) + 2, 3)
n = neg + max(pad, m)

with_scratch_buffer(n) do a
oct_impl_(a, x, n, neg)
String(a)
end
end

function oct_io(io::IO, x::Unsigned, pad::Int, neg::Bool)
m = div(8 * sizeof(x) - leading_zeros(x) + 2, 3)
n = neg + max(pad, m)

with_scratch_buffer(n) do scratch
oct_impl_(scratch, x, n, neg)
write(io, scratch)
end
end

# 2-digit decimal characters ("00":"99")
const _dec_d100 = UInt16[(0x30 + i % 10) << 0x8 + (0x30 + i ÷ 10) for i = 0:99]

function dec(x::Unsigned, pad::Int, neg::Bool)
n = neg + ndigits(x, pad=pad)
a = StringVector(n)
@inline function dec_impl_(a, x::Unsigned, n::Int, neg::Bool)
i = n
@inbounds while i >= 2
d, r = divrem(x, 0x64)
Expand All @@ -717,13 +752,29 @@ function dec(x::Unsigned, pad::Int, neg::Bool)
@inbounds a[i] = 0x30 + (rem(x, 0xa) % UInt8)::UInt8
end
if neg; @inbounds a[1]=0x2d; end
String(a)

nothing
end

function hex(x::Unsigned, pad::Int, neg::Bool)
m = 2 * sizeof(x) - (leading_zeros(x) >> 2)
n = neg + max(pad, m)
a = StringVector(n)
function dec(x::Unsigned, pad::Int, neg::Bool)
n = neg + ndigits(x, pad=pad)

with_scratch_buffer(n) do scratch
dec_impl_(scratch, x, n, neg)
String(scratch)
end
end

function dec_io(io::IO, x::Unsigned, pad::Int, neg::Bool)
n = neg + ndigits(x, pad=pad)

with_scratch_buffer(n) do scratch
dec_impl_(scratch, x, n, neg)
write(io, scratch)
end
end

@inline function hex_impl_(a, x::Unsigned, n::Int, neg::Bool)
i = n
while i >= 2
b = (x % UInt8)::UInt8
Expand All @@ -738,19 +789,35 @@ function hex(x::Unsigned, pad::Int, neg::Bool)
@inbounds a[i] = d + ifelse(d > 0x9, 0x57, 0x30)
end
if neg; @inbounds a[1]=0x2d; end
String(a)

nothing
end

function hex(x::Unsigned, pad::Int, neg::Bool)
m = 2 * sizeof(x) - (Base.leading_zeros(x) >> 2)
n = neg + max(pad, m)

with_scratch_buffer(n) do a
hex_impl_(a, x, n, neg)
String(a)
end
end

function hex_io(io::IO, x::Unsigned, pad::Int, neg::Bool)
m = 2 * sizeof(x) - (leading_zeros(x) >> 2)
n = neg + max(pad, m)

with_scratch_buffer(n) do scratch
hex_impl_(scratch, x, n, neg)
write(io, scratch)
end
end

const base36digits = UInt8['0':'9';'a':'z']
const base62digits = UInt8['0':'9';'A':'Z';'a':'z']

function _base(base::Integer, x::Integer, pad::Int, neg::Bool)
(x >= 0) | (base < 0) || throw(DomainError(x, "For negative `x`, `base` must be negative."))
2 <= abs(base) <= 62 || throw(DomainError(base, "base must satisfy 2 ≤ abs(base) ≤ 62"))
b = (base % Int)::Int
@inline function _base_impl_(a, b::Integer, x::Integer, n::Int, neg::Bool)
digits = abs(b) <= 36 ? base36digits : base62digits
n = neg + ndigits(x, base=b, pad=pad)
a = StringVector(n)
i = n
@inbounds while i > neg
if b > 0
Expand All @@ -763,7 +830,32 @@ function _base(base::Integer, x::Integer, pad::Int, neg::Bool)
i -= 1
end
if neg; @inbounds a[1]=0x2d; end
String(a)

nothing
end

function _base(base::Integer, x::Integer, pad::Int, neg::Bool)
(x >= 0) | (base < 0) || throw(DomainError(x, "For negative `x`, `base` must be negative."))
2 <= abs(base) <= 62 || throw(DomainError(base, "base must satisfy 2 ≤ abs(base) ≤ 62"))
b = (base % Int)::Int
n = neg + ndigits(x, base=b, pad=pad)

with_scratch_buffer(n) do a
_base_impl_(a, b, x, n, neg)
String(a)
end
end

function _base_io(io::IO, base::Integer, x::Integer, pad::Int, neg::Bool)
(x >= 0) | (base < 0) || throw(DomainError(x, "For negative `x`, `base` must be negative."))
2 <= abs(base) <= 62 || throw(DomainError(base, "base must satisfy 2 ≤ abs(base) ≤ 62"))
b = (base % Int)::Int
n = neg + ndigits(x, base=b, pad=pad)

with_scratch_buffer(n) do scratch
_base_impl_(scratch, b, x, n, neg)
write(io, scratch)
end
end

split_sign(n::Integer) = unsigned(abs(n)), n < 0
Expand Down Expand Up @@ -805,6 +897,39 @@ function string(n::Integer; base::Integer = 10, pad::Integer = 1)
end
end

function print_int(io::IO, n::Integer; base::Integer = 10, pad::Integer = 1)
pad = (min(max(pad, typemin(Int)), typemax(Int)) % Int)::Int
if base == 2
(n_positive, neg) = split_sign(n)
bin_io(io, n_positive, pad, neg)
elseif base == 8
(n_positive, neg) = split_sign(n)
oct_io(io, n_positive, pad, neg)
elseif base == 10
(n_positive, neg) = split_sign(n)
dec_io(io, n_positive, pad, neg)
elseif base == 16
(n_positive, neg) = split_sign(n)
hex_io(io, n_positive, pad, neg)
else
_base_io(io, base, base > 0 ? unsigned(abs(n)) : convert(Signed, n), pad, (base>0) & (n<0))
end

return nothing
end

function print_int(io::IO, prefix::Tuple, n::Integer; base::Integer = 10, pad::Integer = 1)
lock(io)
try
print(io, prefix...)
print_int(io, n; base = base, pad = pad)
finally
unlock(io)
end

return nothing
end

string(b::Bool) = b ? "true" : "false"

"""
Expand Down
44 changes: 25 additions & 19 deletions base/ryu/Ryu.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Ryu

import .Base: significand_bits, significand_mask, exponent_bits, exponent_mask, exponent_bias, exponent_max, uinttype
import .Base: with_scratch_buffer

include("utils.jl")
include("shortest.jl")
Expand Down Expand Up @@ -45,9 +46,10 @@ function writeshortest(x::T,
decchar::UInt8=UInt8('.'),
typed::Bool=false,
compact::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(neededdigits(T))
pos = writeshortest(buf, 1, x, plus, space, hash, precision, expchar, padexp, decchar, typed, compact)
return String(resize!(buf, pos - 1))
with_scratch_buffer(neededdigits(T)) do buf
pos = writeshortest(buf, 1, x, plus, space, hash, precision, expchar, padexp, decchar, typed, compact)
return String(@inbounds view(buf, 1:pos - 1))
end
end

"""
Expand All @@ -73,9 +75,10 @@ function writefixed(x::T,
hash::Bool=false,
decchar::UInt8=UInt8('.'),
trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(precision + neededdigits(T))
pos = writefixed(buf, 1, x, precision, plus, space, hash, decchar, trimtrailingzeros)
return String(resize!(buf, pos - 1))
with_scratch_buffer(precision + neededdigits(T)) do buf
pos = writefixed(buf, 1, x, precision, plus, space, hash, decchar, trimtrailingzeros)
return String(@inbounds view(buf, 1:pos - 1))
end
end

"""
Expand Down Expand Up @@ -103,26 +106,29 @@ function writeexp(x::T,
expchar::UInt8=UInt8('e'),
decchar::UInt8=UInt8('.'),
trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(precision + neededdigits(T))
pos = writeexp(buf, 1, x, precision, plus, space, hash, expchar, decchar, trimtrailingzeros)
return String(resize!(buf, pos - 1))
with_scratch_buffer(precision + neededdigits(T)) do buf
pos = writeexp(buf, 1, x, precision, plus, space, hash, expchar, decchar, trimtrailingzeros)
return String(@inbounds view(buf, 1:pos - 1))
end
end

function Base.show(io::IO, x::T, forceuntyped::Bool=false, fromprint::Bool=false) where {T <: Base.IEEEFloat}
compact = get(io, :compact, false)::Bool
buf = Base.StringVector(neededdigits(T))
typed = !forceuntyped && !compact && get(io, :typeinfo, Any) != typeof(x)
pos = writeshortest(buf, 1, x, false, false, true, -1,
(x isa Float32 && !fromprint) ? UInt8('f') : UInt8('e'), false, UInt8('.'), typed, compact)
write(io, resize!(buf, pos - 1))
return
with_scratch_buffer(neededdigits(T)) do buf
typed = !forceuntyped && !compact && get(io, :typeinfo, Any) != typeof(x)
pos = writeshortest(buf, 1, x, false, false, true, -1,
(x isa Float32 && !fromprint) ? UInt8('f') : UInt8('e'), false, UInt8('.'), typed, compact)
write(io, @inbounds view(buf, 1:pos - 1))
return
end
end

function Base.string(x::T) where {T <: Base.IEEEFloat}
buf = Base.StringVector(neededdigits(T))
pos = writeshortest(buf, 1, x, false, false, true, -1,
UInt8('e'), false, UInt8('.'), false, false)
return String(resize!(buf, pos - 1))
with_scratch_buffer(neededdigits(T)) do buf
pos = writeshortest(buf, 1, x, false, false, true, -1,
UInt8('e'), false, UInt8('.'), false, false)
return String(@inbounds view(buf, 1:pos - 1))
end
end

Base.print(io::IO, x::Union{Float16, Float32}) = show(io, x, true, true)
Expand Down
2 changes: 1 addition & 1 deletion base/ryu/shortest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`.
return b, e10
end

function writeshortest(buf::Vector{UInt8}, pos, x::T,
function writeshortest(buf, pos, x::T,
plus=false, space=false, hash=true,
precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'),
typed=false, compact=false) where {T}
Expand Down
Loading