@@ -8,7 +8,8 @@ export is_positive, is_negative;
8
8
export is_nonpositive, is_nonnegative;
9
9
export range;
10
10
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;
12
13
13
14
const min_value: T = 0 as T ;
14
15
const max_value: T = 0 as T - 1 as T ;
@@ -102,10 +103,19 @@ Convert to a string in a given base
102
103
103
104
Fails if `radix` < 2 or `radix` > 16
104
105
" ]
105
- fn to_str ( num : T , radix : uint ) -> str {
106
- assert ( 1 u < radix && radix <= 16 u) ;
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) ]
109
119
fn digit ( n : T ) -> u8 {
110
120
if n <= 9 u as T {
111
121
n as u8 + '0' as u8
@@ -115,36 +125,70 @@ fn to_str(num: T, radix: uint) -> str {
115
125
fail;
116
126
}
117
127
}
118
- if n == 0 u as T { ret "0" ; }
119
128
120
- let mut buf: [ mut u8] = [ mut] ;
121
- vec:: reserve ( buf, 20 u) ; // Enough room to hold any number
129
+ assert ( 1 u < radix && radix <= 16 u) ;
122
130
123
- while n != 0 u 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 -= 1 u;
160
+ assert 0 u < i && i < len;
161
+ * ptr:: mut_offset ( mp, i) = digit ( n % radix) ;
162
+ n /= radix;
163
+ if n == 0 as T { break ; }
164
+ }
127
165
128
- buf += [ 0u8 ] ;
166
+ assert 0 u < i && i < len ;
129
167
130
- let mut start_idx = 0 u;
131
- let mut end_idx = buf. len ( ) - 2 u;
132
- while start_idx < end_idx {
133
- vec:: swap ( buf, start_idx, end_idx) ;
134
- start_idx += 1 u;
135
- end_idx -= 1 u;
136
- }
168
+ if neg {
169
+ i -= 1 u;
170
+ * ptr:: mut_offset ( mp, i) = '-' as u8 ;
171
+ }
137
172
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)
142
175
}
143
176
}
144
177
145
178
#[ doc = "Convert to a string" ]
146
179
fn str ( i : T ) -> str { ret to_str ( i, 10 u) ; }
147
180
181
+ #[ test]
182
+ fn test_to_str ( ) {
183
+ assert to_str ( 0 as T , 10 u) == "0" ;
184
+ assert to_str ( 1 as T , 10 u) == "1" ;
185
+ assert to_str ( 2 as T , 10 u) == "2" ;
186
+ assert to_str ( 11 as T , 10 u) == "11" ;
187
+ assert to_str ( 11 as T , 16 u) == "b" ;
188
+ assert to_str ( 255 as T , 16 u) == "ff" ;
189
+ assert to_str ( 0xff as T , 10 u) == "255" ;
190
+ }
191
+
148
192
#[ test]
149
193
#[ ignore]
150
194
fn test_from_str ( ) {
0 commit comments