@@ -74,32 +74,44 @@ pub fn (mut b Builder) write_byte(data u8) {
7474// write_decimal appends a decimal representation of the number `n` into the builder `b`,
7575// without dynamic allocation. The higher order digits come first, i.e. 6123 will be written
7676// with the digit `6` first, then `1`, then `2` and `3` last.
77- @[direct_array_access]
7877pub fn (mut b Builder) write_decimal (n i64 ) {
7978 if n == 0 {
8079 b.write_u8 (0x30 )
8180 return
8281 }
83- if n == min_i64 {
84- b.write_string (n.str ())
82+ mut mag := u64 (n)
83+ if n < 0 {
84+ b.write_u8 (`-` )
85+ // Wrapping unsigned negation yields the correct magnitude even for `min_i64`,
86+ // whose absolute value does not fit in an i64, so this stays allocation-free for
87+ // every input without a special case for the signed 64-bit minimum.
88+ mag = u64 (0 ) - mag
89+ }
90+ b.write_u_decimal (mag)
91+ }
92+
93+ // write_u_decimal appends a decimal representation of the unsigned number `n` into the
94+ // builder `b`, without dynamic allocation. Unlike `write_decimal`, it covers the entire
95+ // `u64` range (values above `max_i64`). The higher order digits come first, i.e. 6123
96+ // will be written with the digit `6` first, then `1`, then `2` and `3` last.
97+ @[direct_array_access]
98+ pub fn (mut b Builder) write_u_decimal (n u64 ) {
99+ if n == 0 {
100+ b.write_u8 (0x30 )
85101 return
86102 }
87103
88- mut buf := [25 ]u8 {}
89- mut x := if n < 0 { - n } else { n }
90- mut i := 24
104+ mut buf := [20 ]u8 {} // max_u64 == 18446744073709551615, i.e. 20 digits
105+ mut x := n
106+ mut i := 19
91107 for x != 0 {
92108 nextx := x / 10
93109 r := x % 10
94110 buf[i] = u8 (r) + 0x30
95111 x = nextx
96112 i--
97113 }
98- if n < 0 {
99- buf[i] = `-`
100- i--
101- }
102- unsafe { b.write_ptr (& buf[i + 1 ], 24 - i) }
114+ unsafe { b.write_ptr (& buf[i + 1 ], 19 - i) }
103115}
104116
105117// write implements the io.Writer interface, that is why it returns how many bytes were written to the string builder.
0 commit comments