Skip to content

Commit c50a1f6

Browse files
committed
Optimize integer-->string conversions
This avoids invalidations caused by invalidating `StringVector(::Integer)`. This also makes `bin()`, `dec`() and `hex()` slightly faster, but does not change the Printf.
1 parent 6185d24 commit c50a1f6

File tree

1 file changed

+67
-30
lines changed

1 file changed

+67
-30
lines changed

base/intfuncs.jl

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -602,74 +602,111 @@ ndigits(x::Integer; base::Integer=10, pad::Integer=1) = max(pad, ndigits0z(x, ba
602602
## integer to string functions ##
603603

604604
function bin(x::Unsigned, pad::Integer, neg::Bool)
605-
i = neg + max(pad,sizeof(x)<<3-leading_zeros(x))
606-
a = StringVector(i)
605+
m = 8sizeof(x) - leading_zeros(x)::Int
606+
n = neg + max((pad % Int)::Int, m)
607+
a = StringVector(n)
608+
# for i in 0x0:UInt(n-1) # automatic vectorization produces redundant codes
609+
# @inbounds a[n - i] = 0x30 + (((x >> i) % UInt8)::UInt8 & 0x1)
610+
# end
611+
i = n
612+
@inbounds while i >= 4
613+
b = UInt32((x % UInt8)::UInt8)
614+
d = 0x30303030 + ((b * 0x08040201) >> 0x3) & 0x01010101
615+
a[i-3] = (d >> 0x00) % UInt8
616+
a[i-2] = (d >> 0x08) % UInt8
617+
a[i-1] = (d >> 0x10) % UInt8
618+
a[i] = (d >> 0x18) % UInt8
619+
x >>= 0x4
620+
i -= 4
621+
end
607622
while i > neg
608-
@inbounds a[i] = 48+(x&0x1)
609-
x >>= 1
623+
@inbounds a[i] = 0x30 + ((x % UInt8)::UInt8 & 0x1)
624+
x >>= 0x1
610625
i -= 1
611626
end
612627
if neg; @inbounds a[1]=0x2d; end
613628
String(a)
614629
end
615630

616631
function oct(x::Unsigned, pad::Integer, neg::Bool)
617-
i = neg + max(pad,div((sizeof(x)<<3)-leading_zeros(x)+2,3))
618-
a = StringVector(i)
632+
m = div(8sizeof(x) - leading_zeros(x)::Int + 2, 3)
633+
n = neg + max((pad % Int)::Int, m)
634+
a = StringVector(n)
635+
i = n
619636
while i > neg
620-
@inbounds a[i] = 48+(x&0x7)
621-
x >>= 3
637+
@inbounds a[i] = 0x30 + ((x % UInt8)::UInt8 & 0x7)
638+
x >>= 0x3
622639
i -= 1
623640
end
624641
if neg; @inbounds a[1]=0x2d; end
625642
String(a)
626643
end
627644

645+
# 2-digit decimal characters ("00":"99")
646+
const _dec_d100 = UInt16[(0x30 + i % 10) << 0x8 + (0x30 + i ÷ 10) for i = 0:99]
647+
628648
function dec(x::Unsigned, pad::Integer, neg::Bool)
629-
i = neg + ndigits(x, base=10, pad=pad)
630-
a = StringVector(i)
631-
while i > neg
632-
@inbounds a[i] = 48+rem(x,10)
633-
x = oftype(x,div(x,10))
634-
i -= 1
649+
n = neg + ndigits(x, base=10, pad=(pad % Int)::Int)::Int
650+
a = StringVector(n)
651+
i = n
652+
@inbounds while i >= 2
653+
d, r = divrem(x, 0x64)
654+
d100 = _dec_d100[(r % Int)::Int + 1]
655+
a[i-1] = d100 % UInt8
656+
a[i] = (d100 >> 0x8) % UInt8
657+
x = oftype(x, d)
658+
i -= 2
659+
end
660+
if i > neg
661+
@inbounds a[i] = 0x30 + (rem(x, 0xa) % UInt8)::UInt8
635662
end
636663
if neg; @inbounds a[1]=0x2d; end
637664
String(a)
638665
end
639666

640667
function hex(x::Unsigned, pad::Integer, neg::Bool)
641-
i = neg + max(pad,(sizeof(x)<<1)-(leading_zeros(x)>>2))
642-
a = StringVector(i)
643-
while i > neg
644-
d = x & 0xf
645-
@inbounds a[i] = 48+d+39*(d>9)
646-
x >>= 4
647-
i -= 1
668+
m = 2sizeof(x) - (leading_zeros(x)::Int >> 2)
669+
n = neg + max((pad % Int)::Int, m)
670+
a = StringVector(n)
671+
i = n
672+
while i >= 2
673+
b = (x % UInt8)::UInt8
674+
d1, d2 = b >> 0x4, b & 0xf
675+
@inbounds a[i-1] = d1 + ifelse(d1 > 0x9, 0x57, 0x30)
676+
@inbounds a[i] = d2 + ifelse(d2 > 0x9, 0x57, 0x30)
677+
x >>= 0x8
678+
i -= 2
679+
end
680+
if i > neg
681+
d = (x % UInt8)::UInt8 & 0xf
682+
@inbounds a[i] = d + ifelse(d > 0x9, 0x57, 0x30)
648683
end
649684
if neg; @inbounds a[1]=0x2d; end
650685
String(a)
651686
end
652687

653-
const base36digits = ['0':'9';'a':'z']
654-
const base62digits = ['0':'9';'A':'Z';'a':'z']
688+
const base36digits = UInt8['0':'9';'a':'z']
689+
const base62digits = UInt8['0':'9';'A':'Z';'a':'z']
655690

656-
function _base(b::Integer, x::Integer, pad::Integer, neg::Bool)
657-
(x >= 0) | (b < 0) || throw(DomainError(x, "For negative `x`, `b` must be negative."))
691+
function _base(base::Integer, x::Integer, pad::Integer, neg::Bool)
692+
b = (base % Int)::Int
693+
(x >= 0) | (b < 0) || throw(DomainError(x, "For negative `x`, `base` must be negative."))
658694
2 <= abs(b) <= 62 || throw(DomainError(b, "base must satisfy 2 ≤ abs(base) ≤ 62"))
659695
digits = abs(b) <= 36 ? base36digits : base62digits
660-
i = neg + ndigits(x, base=b, pad=pad)
661-
a = StringVector(i)
696+
n = neg + ndigits(x, base=b, pad=(pad % Int)::Int)::Int
697+
a = StringVector(n)
698+
i = n
662699
@inbounds while i > neg
663700
if b > 0
664-
a[i] = digits[1+rem(x,b)]
701+
a[i] = digits[1 + (rem(x, b) % Int)::Int]
665702
x = div(x,b)
666703
else
667-
a[i] = digits[1+mod(x,-b)]
704+
a[i] = digits[1 + (mod(x, -b) % Int)::Int]
668705
x = cld(x,b)
669706
end
670707
i -= 1
671708
end
672-
if neg; a[1]='-'; end
709+
if neg; @inbounds a[1]=0x2d; end
673710
String(a)
674711
end
675712

0 commit comments

Comments
 (0)