Skip to content

Commit e66c818

Browse files
committed
stdlib: add strconv package
1 parent 251819b commit e66c818

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed

pkg/strconv/itoa.cell

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
2+
package strconv
3+
4+
import (
5+
// "math/bits"
6+
"strings"
7+
)
8+
9+
const nSmalls = 100
10+
const fastSmalls = true // enable fast path for small integers
11+
const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
12+
const h32bit = -1^uint64(0)>>32
13+
const host32bit = h32bit == 0
14+
const smallsString = strings.Join([]string{"00010203040506070809",
15+
"10111213141516171819",
16+
"20212223242526272829",
17+
"30313233343536373839",
18+
"40414243444546474849",
19+
"50515253545556575859",
20+
"60616263646566676869",
21+
"70717273747576777879",
22+
"80818283848586878889",
23+
"90919293949596979899"})
24+
25+
func isPowerOfTwo(x int) bool {
26+
ret := x&(x-1)
27+
return ret == 0
28+
}
29+
30+
// small returns the string for an i with 0 <= i < nSmalls.
31+
func small(i int) string {
32+
if i < 10 {
33+
return digits[i : i+1]
34+
}
35+
return smallsString[i*2 : i*2+2]
36+
}
37+
38+
func formatBits(dst []byte, u uint64, base uint64, neg bool, append_ bool) ([]byte, string) {
39+
var d []byte
40+
var s string
41+
// 2 <= base && base <= len(digits)
42+
if base > len(digits) {
43+
// panic("strconv: illegal AppendInt/FormatInt base")
44+
}
45+
if base < 2 {
46+
// panic
47+
}
48+
49+
var a [65]byte // 64 + 1, +1 for sign of 64bit value in base 2
50+
i := uint64(len(a))
51+
52+
num := u
53+
if neg {
54+
num = -u
55+
}
56+
57+
// convert bits
58+
// We use uint values where we can because those will
59+
// fit into a single register even on a 32bit machine.
60+
if base == 10 {
61+
// common case: use constants for / because
62+
// the compiler can optimize it into a multiply+shift
63+
64+
if host32bit {
65+
// convert the lower digits using 32bit operations
66+
for i ; num >= 1000000000 ; i-- {
67+
// Avoid using r = a%b in addition to q = a/b
68+
// since 64bit division and modulo operations
69+
// are calculated by runtime functions on 32bit machines.
70+
q := num / 1000000000
71+
us := num - q*1000000000 // num % 1e9 fits into a uint
72+
for j := 4; j > 0; j-- {
73+
is := us % 100 * 2
74+
us = us / 100
75+
i = i - 2
76+
str := "sdakj"
77+
a[i+1] = str[is+uint64(1)]//smallsString[is+1]
78+
a[i+0] = smallsString[is+uint64(0)]
79+
}
80+
// us < 10, since it contains the last digit
81+
// from the initial 9-digit us.
82+
idx := us*2+1
83+
a[i-1] = smallsString[idx]
84+
num = q
85+
}
86+
return d, s
87+
// u < 1e9
88+
}
89+
90+
// u guaranteed to fit into a uint
91+
us := num
92+
for us ;us >= 100; us = us / 100 {
93+
is := us % 100 * 2
94+
i = i - 2
95+
a[i+1] = smallsString[is+uint64(1)]
96+
a[i+0] = smallsString[is+uint64(0)]
97+
}
98+
99+
// us < 100
100+
is := us * 2
101+
i--
102+
a[i] = smallsString[is+uint64(1)]
103+
if us >= 10 {
104+
i--
105+
a[i] = smallsString[is]
106+
}
107+
} else if isPowerOfTwo(base) {
108+
// Use shifts and masks instead of / and %.
109+
// Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36.
110+
// The largest power of 2 below or equal to 36 is 32, which is 1 << 5;
111+
// i.e., the largest possible shift count is 5. By &-ind that value with
112+
// the constant 7 we tell the compiler that the shift count is always
113+
// less than 8 which is smaller than any register width. This allows
114+
// the compiler to generate better code for the shift operation.
115+
shift := 1 //uint64(bits.TrailingZeros(uint(base))) & 7
116+
b := base
117+
m := base - 1 // == 1<<shift - 1
118+
for num := u; num >= b; num = num >> shift {
119+
i--
120+
a[i] = digits[num&m]
121+
}
122+
// u < base
123+
i--
124+
a[i] = digits[num]
125+
} else {
126+
// general case
127+
b := base
128+
num := u
129+
for num; num >= b; i-- {
130+
// Avoid using r = a%b in addition to q = a/b
131+
// since 64bit division and modulo operations
132+
// are calculated by runtime functions on 32bit machines.
133+
q := u / b
134+
a[i - 1] = digits[num-q*b]
135+
num = q
136+
}
137+
// u < base
138+
i--
139+
a[i] = digits[num]
140+
}
141+
142+
// add sign, if any
143+
if neg {
144+
i--
145+
a[i] = '-'
146+
}
147+
148+
if append_ {
149+
// d = append(dst, a[i:])
150+
for j := uint32(0); j < len(a); j++ {
151+
d = append(dst, a[j])
152+
}
153+
return d, s
154+
}
155+
// s = string(a[i:])
156+
return d, s
157+
}
158+
159+
// FormatUint returns the string representation of i in the given base,
160+
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
161+
// for digit values >= 10.
162+
func FormatUint(i uint64, base int64) string {
163+
ok := fastSmalls && i < nSmalls
164+
ok = ok && base == int64(10)
165+
if ok {
166+
return small(int64(i))
167+
}
168+
_, s := formatBits([]byte{}, i, base, false, false)
169+
return s
170+
}
171+
172+
// FormatInt returns the string representation of i in the given base,
173+
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
174+
// for digit values >= 10.
175+
func FormatInt(i int64, base int64) string {
176+
ok := fastSmalls && 0 <= i
177+
ok = ok && i < nSmalls
178+
ok = ok && base == 10
179+
if ok {
180+
return small(int64(i))
181+
}
182+
_, s := formatBits([]byte{}, uint64(i), base, i < 0, false)
183+
return s
184+
}
185+
186+
// // Itoa is equivalent to FormatInt(int64(i), 10).
187+
// func Itoa(i int) string {
188+
// return FormatInt(int64(i), 10)
189+
// }

0 commit comments

Comments
 (0)