Skip to content

Commit 036d4aa

Browse files
to_string method for standard integers with radix.
1 parent cad4e6a commit 036d4aa

File tree

2 files changed

+187
-39
lines changed

2 files changed

+187
-39
lines changed

builtin/builtin.mbti

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ impl Int {
454454
to_int16(Int) -> Int16
455455
to_int64(Int) -> Int64
456456
to_json(Int) -> Json
457-
to_string(Int) -> String
457+
to_string(Int, radix~ : Int = ..) -> String
458458
to_uint(Int) -> UInt //deprecated
459459
to_uint16(Int) -> UInt16
460460
to_uint64(Int) -> UInt64
@@ -466,7 +466,7 @@ impl Int16 {
466466
to_byte(Int16) -> Byte
467467
to_int(Int16) -> Int
468468
to_int64(Int16) -> Int64
469-
to_string(Int16) -> String
469+
to_string(Int16, radix~ : Int = ..) -> String
470470
}
471471

472472
impl Int64 {
@@ -501,7 +501,7 @@ impl Int64 {
501501
to_int(Int64) -> Int
502502
to_int16(Int64) -> Int16
503503
to_json(Int64) -> Json
504-
to_string(Int64) -> String
504+
to_string(Int64, radix~ : Int = ..) -> String
505505
to_uint16(Int64) -> UInt16
506506
to_uint64(Int64) -> UInt64 //deprecated
507507
until(Int64, Int64, step~ : Int64 = .., inclusive~ : Bool = ..) -> Iter[Int64]
@@ -536,7 +536,7 @@ impl UInt {
536536
to_float(UInt) -> Float
537537
to_int(UInt) -> Int //deprecated
538538
to_json(UInt) -> Json
539-
to_string(UInt) -> String
539+
to_string(UInt, radix~ : Int = ..) -> String
540540
to_uint64(UInt) -> UInt64
541541
trunc_double(Double) -> UInt
542542
upto(UInt, UInt, inclusive~ : Bool = ..) -> Iter[UInt] //deprecated
@@ -546,7 +546,7 @@ impl UInt16 {
546546
to_byte(UInt16) -> Byte
547547
to_int(UInt16) -> Int
548548
to_int64(UInt16) -> Int64
549-
to_string(UInt16) -> String
549+
to_string(UInt16, radix~ : Int = ..) -> String
550550
}
551551

552552
impl UInt64 {
@@ -580,7 +580,7 @@ impl UInt64 {
580580
to_int(UInt64) -> Int
581581
to_int64(UInt64) -> Int64 //deprecated
582582
to_json(UInt64) -> Json
583-
to_string(UInt64) -> String
583+
to_string(UInt64, radix~ : Int = ..) -> String
584584
to_uint(UInt64) -> UInt
585585
trunc_double(Double) -> UInt64
586586
upto(UInt64, UInt64, inclusive~ : Bool = ..) -> Iter[UInt64] //deprecated

builtin/to_string.mbt

Lines changed: 181 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ pub fn Bool::to_string(self : Bool) -> String {
2222
}
2323

2424
///|
25-
pub fn Int64::to_string(self : Int64) -> String {
25+
const ALPHABET : String = "0123456789abcdefghijklmnopqrstuvwxyz"
26+
27+
///|
28+
pub fn Int64::to_string(self : Int64, radix~ : Int = 10) -> String {
2629
fn abs(n : Int64) -> Int64 {
2730
if n < 0L {
2831
0L - n
@@ -31,27 +34,36 @@ pub fn Int64::to_string(self : Int64) -> String {
3134
}
3235
}
3336

34-
// The min and max value of i64 are -9223372036854775808 and 9223372036854775807,
35-
// so max=20 is enough.
36-
37-
let buf = StringBuilder::new(size_hint=20)
37+
let size_hint = match radix {
38+
2..<7 => 70 // max length is 64, 70 is enough
39+
8..<15 => 30 // max length is 23, 30 is enough
40+
16..=36 => 20 // max length is 17, 20 is enough
41+
_ => abort("radix must be between 2 and 36")
42+
}
43+
let buf = StringBuilder::new(size_hint~)
3844
if self < 0L {
3945
buf.write_char('-')
4046
}
41-
fn write_digits(num) {
42-
let num2 = num / 10L
47+
let radix : Int64 = radix.to_int64()
48+
fn write_digits(num : Int64) {
49+
let num2 = num / radix
4350
if num2 != 0L {
4451
write_digits(num2)
4552
}
46-
buf.write_char(Char::from_int(abs(num % 10L).to_int() + 48))
53+
buf.write_char(ALPHABET[abs(num % radix).to_int()])
4754
}
4855

49-
write_digits(self)
56+
write_digits(abs(self))
5057
buf.to_string()
5158
}
5259

5360
///|
54-
pub fn Int::to_string(self : Int) -> String {
61+
pub impl Show for Int64 with to_string(self) {
62+
self.to_string(radix=10)
63+
}
64+
65+
///|
66+
pub fn Int::to_string(self : Int, radix~ : Int = 10) -> String {
5567
fn abs(n : Int) -> Int {
5668
if n < 0 {
5769
0 - n
@@ -60,40 +72,60 @@ pub fn Int::to_string(self : Int) -> String {
6072
}
6173
}
6274

63-
// The min and max value of i32 are -2147483648 and 2147483647,
64-
// so max=11 is enough.
65-
66-
let buf = StringBuilder::new()
75+
let size_hint = match radix {
76+
2..<7 => 36 // max length is 32, 36 is enough
77+
8..<15 => 18 // max length is 12, 18 is enough
78+
16..=36 => 10 // max length is 8, 10 is enough
79+
_ => abort("radix must be between 2 and 36")
80+
}
81+
let buf = StringBuilder::new(size_hint~)
6782
if self < 0 {
6883
buf.write_char('-')
6984
}
70-
fn write_digits(num) {
71-
let num2 = num / 10
85+
fn write_digits(num : Int) {
86+
let num2 = num / radix
7287
if num2 != 0 {
7388
write_digits(num2)
7489
}
75-
buf.write_char(Char::from_int(abs(num % 10) + 48))
90+
buf.write_char(ALPHABET[abs(num % radix)])
7691
}
7792

78-
write_digits(self)
93+
write_digits(abs(self))
7994
buf.to_string()
8095
}
8196

8297
///|
83-
pub fn UInt::to_string(self : UInt) -> String {
84-
let buf = StringBuilder::new()
85-
fn write_digits(num) {
86-
let num2 = num / 10U
98+
pub impl Show for Int with to_string(self) {
99+
self.to_string(radix=10)
100+
}
101+
102+
///|
103+
pub fn UInt::to_string(self : UInt, radix~ : Int = 10) -> String {
104+
let size_hint = match radix {
105+
2..<7 => 36 // max length is 32, 36 is enough
106+
8..<15 => 18 // max length is 11, 18 is enough
107+
16..=36 => 10 // max length is 8, 10 is enough
108+
_ => abort("radix must be between 2 and 36")
109+
}
110+
let buf = StringBuilder::new(size_hint~)
111+
let radix : UInt = radix.reinterpret_as_uint()
112+
fn write_digits(num : UInt) {
113+
let num2 = num / radix
87114
if num2 != 0U {
88115
write_digits(num2)
89116
}
90-
buf.write_char(Char::from_int((num % 10U).reinterpret_as_int() + 48))
117+
buf.write_char(ALPHABET[(num % radix).reinterpret_as_int()])
91118
}
92119

93120
write_digits(self)
94121
buf.to_string()
95122
}
96123

124+
///|
125+
pub impl Show for UInt with to_string(self) {
126+
self.to_string(radix=10)
127+
}
128+
97129
///|
98130
test "UInt::to_string" {
99131
inspect!(0U, content="0")
@@ -102,28 +134,144 @@ test "UInt::to_string" {
102134
}
103135

104136
///|
105-
pub fn UInt64::to_string(self : UInt64) -> String {
106-
let buf = StringBuilder::new()
137+
pub fn UInt64::to_string(self : UInt64, radix~ : Int = 10) -> String {
138+
let size_hint = match radix {
139+
2..<7 => 70 // max length is 64, 70 is enough
140+
8..<15 => 30 // max length is 23, 30 is enough
141+
16..=36 => 20 // max length is 17, 20 is enough
142+
_ => abort("radix must be between 2 and 36")
143+
}
144+
let buf = StringBuilder::new(size_hint~)
145+
let radix : UInt64 = radix.to_uint64()
107146
fn write_digits(num : UInt64) {
108-
let num2 = num / 10UL
147+
let num2 = num / radix
109148
if num2 != 0UL {
110149
write_digits(num2)
111150
}
112-
buf.write_char(
113-
Char::from_int((num % 10UL).reinterpret_as_int64().to_int() + 48),
114-
)
151+
buf.write_char(ALPHABET[(num % radix).to_int()])
115152
}
116153

117154
write_digits(self)
118155
buf.to_string()
119156
}
120157

121158
///|
122-
pub fn Int16::to_string(self : Int16) -> String {
123-
self.to_int().to_string()
159+
pub impl Show for UInt64 with to_string(self) {
160+
self.to_string(radix=10)
161+
}
162+
163+
///|
164+
pub fn Int16::to_string(self : Int16, radix~ : Int = 10) -> String {
165+
self.to_int().to_string(radix~)
166+
}
167+
168+
///|
169+
pub impl Show for Int16 with to_string(self) {
170+
self.to_string(radix=10)
171+
}
172+
173+
///|
174+
pub fn UInt16::to_string(self : UInt16, radix~ : Int = 10) -> String {
175+
self.to_int().to_string(radix~)
176+
}
177+
178+
///|
179+
pub impl Show for UInt16 with to_string(self) {
180+
self.to_string(radix=10)
181+
}
182+
183+
///|
184+
test "to_string" {
185+
assert_eq!((0x100).to_string(), "256")
186+
assert_eq!("\{0x100}", "256")
187+
assert_eq!(0x200U.to_string(), "512")
188+
assert_eq!("\{0x200U}", "512")
189+
assert_eq!(0x300L.to_string(), "768")
190+
assert_eq!("\{0x300L}", "768")
191+
assert_eq!(0x400UL.to_string(), "1024")
192+
assert_eq!("\{0x400UL}", "1024")
193+
}
194+
195+
///|
196+
test "to_string with radix" {
197+
// Binary
198+
inspect!((0).to_string(radix=2), content="0")
199+
inspect!((1).to_string(radix=2), content="1")
200+
inspect!((2).to_string(radix=2), content="10")
201+
inspect!((255).to_string(radix=2), content="11111111")
202+
inspect!((-255).to_string(radix=2), content="-11111111")
203+
204+
// Octal
205+
inspect!((0).to_string(radix=8), content="0")
206+
inspect!((8).to_string(radix=8), content="10")
207+
inspect!((64).to_string(radix=8), content="100")
208+
inspect!((-64).to_string(radix=8), content="-100")
209+
210+
// Decimal
211+
inspect!((0).to_string(radix=10), content="0")
212+
inspect!((123).to_string(radix=10), content="123")
213+
inspect!((-123).to_string(radix=10), content="-123")
214+
inspect!(
215+
0x7fff_ffff_ffff_ffffL.to_string(radix=10),
216+
content="9223372036854775807",
217+
)
218+
inspect!(
219+
0x8000_0000_0000_0000L.to_string(radix=10),
220+
content="-9223372036854775808",
221+
)
222+
223+
// Hexadecimal
224+
inspect!((0).to_string(radix=16), content="0")
225+
inspect!((0x11).to_string(radix=16), content="11")
226+
inspect!((0x15ef).to_string(radix=16), content="15ef")
227+
inspect!((-0xabcd).to_string(radix=16), content="-abcd")
228+
inspect!(
229+
(1.0 : Float).reinterpret_as_int().to_string(radix=16),
230+
content="3f800000",
231+
)
232+
233+
// UInt
234+
inspect!(0U.to_string(radix=16), content="0")
235+
inspect!(0x1AU.to_string(radix=16), content="1a")
236+
inspect!(0xabcdU.to_string(radix=16), content="abcd")
237+
inspect!(
238+
(-2.0 : Float).reinterpret_as_uint().to_string(radix=16),
239+
content="c0000000",
240+
)
241+
inspect!((-1).reinterpret_as_uint().to_string(radix=16), content="ffffffff")
242+
243+
// Int64
244+
inspect!(0L.to_string(radix=16), content="0")
245+
inspect!(0x2fL.to_string(radix=16), content="2f")
246+
inspect!(0xf0aeL.to_string(radix=16), content="f0ae")
247+
inspect!((-0x1234eacbL).to_string(radix=16), content="-1234eacb")
248+
inspect!(
249+
1.0.reinterpret_as_uint64().to_string(radix=16),
250+
content="3ff0000000000000",
251+
)
252+
253+
// UInt64
254+
inspect!(0UL.to_string(radix=16), content="0")
255+
inspect!(0x11UL.to_string(radix=16), content="11")
256+
inspect!(0x12bdUL.to_string(radix=16), content="12bd")
257+
inspect!(
258+
(-1L).reinterpret_as_uint64().to_string(radix=16),
259+
content="ffffffffffffffff",
260+
)
261+
inspect!(
262+
2.0.reinterpret_as_uint64().to_string(radix=16),
263+
content="4000000000000000",
264+
)
124265
}
125266

126267
///|
127-
pub fn UInt16::to_string(self : UInt16) -> String {
128-
self.to_int().to_string()
268+
test "panic to_string_by_radix/illegal_radix" {
269+
ignore((1).to_string(radix=1))
270+
ignore((1).to_string(radix=37))
271+
ignore(1L.to_string(radix=0))
272+
ignore(1L.to_string(radix=42))
273+
ignore(1U.to_string(radix=-1))
274+
ignore(1U.to_string(radix=73))
275+
ignore(1UL.to_string(radix=-100))
276+
ignore(1UL.to_string(radix=100))
129277
}

0 commit comments

Comments
 (0)