Skip to content

Commit 7803488

Browse files
committed
Implement stack-only variants of int/uint str conversion and output.
1 parent 903033b commit 7803488

File tree

3 files changed

+84
-29
lines changed

3 files changed

+84
-29
lines changed

src/libcore/int-template.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export is_nonpositive, is_nonnegative;
99
export range;
1010
export compl;
1111
export abs;
12-
export parse_buf, from_str, to_str, str;
12+
export parse_buf, from_str, to_str, to_str_bytes, str;
1313

1414
const min_value: T = -1 as T << (inst::bits - 1 as T);
1515
const max_value: T = min_value - 1 as T;
@@ -96,6 +96,14 @@ fn to_str(n: T, radix: uint) -> str {
9696
} else { uint::to_str(n as uint, radix) };
9797
}
9898

99+
fn to_str_bytes<U>(n: T, radix: uint, f: fn([u8]/&) -> U) -> U {
100+
if n < 0 as T {
101+
uint::to_str_bytes(true, -n as uint, radix, f)
102+
} else {
103+
uint::to_str_bytes(false, n as uint, radix, f)
104+
}
105+
}
106+
99107
#[doc = "Convert to a string"]
100108
fn str(i: T) -> str { ret to_str(i, 10u); }
101109

src/libcore/io.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ fn u64_from_be_bytes(data: [u8], start: uint, size: uint) -> u64 {
503503
impl writer_util for writer {
504504
fn write_char(ch: char) {
505505
if ch as uint < 128u {
506-
self.write([ch as u8]);
506+
self.write([ch as u8]/&);
507507
} else {
508508
self.write_str(str::from_char(ch));
509509
}
@@ -513,9 +513,12 @@ impl writer_util for writer {
513513
self.write_str(s);
514514
self.write_str("\n"/&);
515515
}
516-
fn write_int(n: int) { self.write_str(int::to_str(n, 10u)); }
517-
fn write_uint(n: uint) { self.write_str(uint::to_str(n, 10u)); }
518-
516+
fn write_int(n: int) {
517+
int::to_str_bytes(n, 10u) {|buf| self.write(buf) }
518+
}
519+
fn write_uint(n: uint) {
520+
uint::to_str_bytes(false, n, 10u) {|buf| self.write(buf) }
521+
}
519522
fn write_le_uint(n: uint, size: uint) {
520523
u64_to_le_bytes(n as u64, size) {|v| self.write(v); }
521524
}

src/libcore/uint-template.rs

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export is_positive, is_negative;
88
export is_nonpositive, is_nonnegative;
99
export range;
1010
export compl;
11-
export to_str, from_str, from_str_radix, str, parse_buf;
11+
export to_str, to_str_bytes;
12+
export from_str, from_str_radix, str, parse_buf;
1213

1314
const min_value: T = 0 as T;
1415
const max_value: T = 0 as T - 1 as T;
@@ -102,10 +103,19 @@ Convert to a string in a given base
102103
103104
Fails if `radix` < 2 or `radix` > 16
104105
"]
105-
fn to_str(num: T, radix: uint) -> str {
106-
assert (1u < radix && radix <= 16u);
107-
let mut n = num;
108-
let radix = radix as T;
106+
fn to_str(num: T, radix: uint) -> str unsafe {
107+
to_str_bytes(false, num, radix) {|slice|
108+
vec::unpack_slice(slice) {|p, len|
109+
str::unsafe::from_buf_len(p, len)
110+
}
111+
}
112+
}
113+
114+
#[doc = "Low-level helper routine for string conversion."]
115+
fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
116+
f: fn([u8]/&) -> U) -> U unsafe {
117+
118+
#[inline(always)]
109119
fn digit(n: T) -> u8 {
110120
if n <= 9u as T {
111121
n as u8 + '0' as u8
@@ -115,36 +125,70 @@ fn to_str(num: T, radix: uint) -> str {
115125
fail;
116126
}
117127
}
118-
if n == 0u as T { ret "0"; }
119128

120-
let mut buf: [mut u8] = [mut];
121-
vec::reserve(buf, 20u); // Enough room to hold any number
129+
assert (1u < radix && radix <= 16u);
122130

123-
while n != 0u as T {
124-
buf += [digit(n % radix)];
125-
n /= radix;
126-
}
131+
// Enough room to hold any number in any radix.
132+
// Worst case: 64-bit number, binary-radix, with
133+
// a leading negative sign = 65 bytes.
134+
let buf : [mut u8]/65 =
135+
[mut
136+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
137+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
138+
139+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
140+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
141+
142+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
143+
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
144+
145+
0u8,0u8,0u8,0u8,0u8
146+
]/65;
147+
148+
// FIXME: post-snapshot, you can do this without
149+
// the raw pointers and unsafe bits, and the
150+
// codegen will prove it's all in-bounds, no
151+
// extra cost.
152+
153+
vec::unpack_slice(buf) {|p, len|
154+
let mp = p as *mut u8;
155+
let mut i = len;
156+
let mut n = num;
157+
let radix = radix as T;
158+
loop {
159+
i -= 1u;
160+
assert 0u < i && i < len;
161+
*ptr::mut_offset(mp, i) = digit(n % radix);
162+
n /= radix;
163+
if n == 0 as T { break; }
164+
}
127165

128-
buf += [0u8];
166+
assert 0u < i && i < len;
129167

130-
let mut start_idx = 0u;
131-
let mut end_idx = buf.len() - 2u;
132-
while start_idx < end_idx {
133-
vec::swap(buf, start_idx, end_idx);
134-
start_idx += 1u;
135-
end_idx -= 1u;
136-
}
168+
if neg {
169+
i -= 1u;
170+
*ptr::mut_offset(mp, i) = '-' as u8;
171+
}
137172

138-
unsafe {
139-
let s = unsafe::reinterpret_cast(buf);
140-
unsafe::forget(buf);
141-
ret s;
173+
vec::unsafe::form_slice(ptr::offset(p, i),
174+
len - i, f)
142175
}
143176
}
144177

145178
#[doc = "Convert to a string"]
146179
fn str(i: T) -> str { ret to_str(i, 10u); }
147180

181+
#[test]
182+
fn test_to_str() {
183+
assert to_str(0 as T, 10u) == "0";
184+
assert to_str(1 as T, 10u) == "1";
185+
assert to_str(2 as T, 10u) == "2";
186+
assert to_str(11 as T, 10u) == "11";
187+
assert to_str(11 as T, 16u) == "b";
188+
assert to_str(255 as T, 16u) == "ff";
189+
assert to_str(0xff as T, 10u) == "255";
190+
}
191+
148192
#[test]
149193
#[ignore]
150194
fn test_from_str() {

0 commit comments

Comments
 (0)