Skip to content

Commit 8fe6fc1

Browse files
committed
Change char::escape_{default,unicode} to take callbacks instead of allocating
strings
1 parent 2b3569a commit 8fe6fc1

File tree

4 files changed

+73
-56
lines changed

4 files changed

+73
-56
lines changed

src/libstd/char.rs

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
1313
use container::Container;
1414
use option::{None, Option, Some};
15-
use str;
16-
use str::{StrSlice, OwnedStr};
17-
use u32;
18-
use uint;
15+
use str::StrSlice;
1916
use unicode::{derived_property, general_category};
2017

18+
#[cfg(test)] use str::OwnedStr;
19+
2120
#[cfg(not(test))] use cmp::{Eq, Ord};
2221
#[cfg(not(test))] use num::Zero;
2322

@@ -202,21 +201,21 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
202201
/// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
203202
/// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
204203
///
205-
pub fn escape_unicode(c: char) -> ~str {
206-
let s = u32::to_str_radix(c as u32, 16u);
207-
let (c, pad) = cond!(
208-
(c <= '\xff') { ('x', 2u) }
209-
(c <= '\uffff') { ('u', 4u) }
210-
_ { ('U', 8u) }
204+
pub fn escape_unicode(c: char, f: &fn(char)) {
205+
// avoid calling str::to_str_radix because we don't really need to allocate
206+
// here.
207+
f('\\');
208+
let pad = cond!(
209+
(c <= '\xff') { f('x'); 2 }
210+
(c <= '\uffff') { f('u'); 4 }
211+
_ { f('U'); 8 }
211212
);
212-
assert!(s.len() <= pad);
213-
let mut out = ~"\\";
214-
out.push_str(str::from_char(c));
215-
for uint::range(s.len(), pad) |_| {
216-
out.push_str("0");
213+
for int::range_step(4 * (pad - 1), -1, -4) |offset| {
214+
match ((c as u32) >> offset) & 0xf {
215+
i @ 0 .. 9 => { f('0' + i as char); }
216+
i => { f('a' + (i - 10) as char); }
217+
}
217218
}
218-
out.push_str(s);
219-
out
220219
}
221220

222221
///
@@ -231,16 +230,16 @@ pub fn escape_unicode(c: char) -> ~str {
231230
/// - Any other chars in the range [0x20,0x7e] are not escaped.
232231
/// - Any other chars are given hex unicode escapes; see `escape_unicode`.
233232
///
234-
pub fn escape_default(c: char) -> ~str {
233+
pub fn escape_default(c: char, f: &fn(char)) {
235234
match c {
236-
'\t' => ~"\\t",
237-
'\r' => ~"\\r",
238-
'\n' => ~"\\n",
239-
'\\' => ~"\\\\",
240-
'\'' => ~"\\'",
241-
'"' => ~"\\\"",
242-
'\x20' .. '\x7e' => str::from_char(c),
243-
_ => c.escape_unicode(),
235+
'\t' => { f('\\'); f('t'); }
236+
'\r' => { f('\\'); f('r'); }
237+
'\n' => { f('\\'); f('n'); }
238+
'\\' => { f('\\'); f('\\'); }
239+
'\'' => { f('\\'); f('\''); }
240+
'"' => { f('\\'); f('"'); }
241+
'\x20' .. '\x7e' => { f(c); }
242+
_ => c.escape_unicode(f),
244243
}
245244
}
246245

@@ -274,8 +273,8 @@ pub trait Char {
274273
fn is_digit_radix(&self, radix: uint) -> bool;
275274
fn to_digit(&self, radix: uint) -> Option<uint>;
276275
fn from_digit(num: uint, radix: uint) -> Option<char>;
277-
fn escape_unicode(&self) -> ~str;
278-
fn escape_default(&self) -> ~str;
276+
fn escape_unicode(&self, f: &fn(char));
277+
fn escape_default(&self, f: &fn(char));
279278
fn len_utf8_bytes(&self) -> uint;
280279
}
281280

@@ -302,9 +301,9 @@ impl Char for char {
302301

303302
fn from_digit(num: uint, radix: uint) -> Option<char> { from_digit(num, radix) }
304303

305-
fn escape_unicode(&self) -> ~str { escape_unicode(*self) }
304+
fn escape_unicode(&self, f: &fn(char)) { escape_unicode(*self, f) }
306305

307-
fn escape_default(&self) -> ~str { escape_default(*self) }
306+
fn escape_default(&self, f: &fn(char)) { escape_default(*self, f) }
308307

309308
fn len_utf8_bytes(&self) -> uint { len_utf8_bytes(*self) }
310309
}
@@ -392,27 +391,37 @@ fn test_is_digit() {
392391

393392
#[test]
394393
fn test_escape_default() {
395-
assert_eq!('\n'.escape_default(), ~"\\n");
396-
assert_eq!('\r'.escape_default(), ~"\\r");
397-
assert_eq!('\''.escape_default(), ~"\\'");
398-
assert_eq!('"'.escape_default(), ~"\\\"");
399-
assert_eq!(' '.escape_default(), ~" ");
400-
assert_eq!('a'.escape_default(), ~"a");
401-
assert_eq!('~'.escape_default(), ~"~");
402-
assert_eq!('\x00'.escape_default(), ~"\\x00");
403-
assert_eq!('\x1f'.escape_default(), ~"\\x1f");
404-
assert_eq!('\x7f'.escape_default(), ~"\\x7f");
405-
assert_eq!('\xff'.escape_default(), ~"\\xff");
406-
assert_eq!('\u011b'.escape_default(), ~"\\u011b");
407-
assert_eq!('\U0001d4b6'.escape_default(), ~"\\U0001d4b6");
394+
fn string(c: char) -> ~str {
395+
let mut result = ~"";
396+
do escape_default(c) |c| { result.push_char(c); }
397+
return result;
398+
}
399+
assert_eq!(string('\n'), ~"\\n");
400+
assert_eq!(string('\r'), ~"\\r");
401+
assert_eq!(string('\''), ~"\\'");
402+
assert_eq!(string('"'), ~"\\\"");
403+
assert_eq!(string(' '), ~" ");
404+
assert_eq!(string('a'), ~"a");
405+
assert_eq!(string('~'), ~"~");
406+
assert_eq!(string('\x00'), ~"\\x00");
407+
assert_eq!(string('\x1f'), ~"\\x1f");
408+
assert_eq!(string('\x7f'), ~"\\x7f");
409+
assert_eq!(string('\xff'), ~"\\xff");
410+
assert_eq!(string('\u011b'), ~"\\u011b");
411+
assert_eq!(string('\U0001d4b6'), ~"\\U0001d4b6");
408412
}
409413
410414
#[test]
411415
fn test_escape_unicode() {
412-
assert_eq!('\x00'.escape_unicode(), ~"\\x00");
413-
assert_eq!('\n'.escape_unicode(), ~"\\x0a");
414-
assert_eq!(' '.escape_unicode(), ~"\\x20");
415-
assert_eq!('a'.escape_unicode(), ~"\\x61");
416-
assert_eq!('\u011b'.escape_unicode(), ~"\\u011b");
417-
assert_eq!('\U0001d4b6'.escape_unicode(), ~"\\U0001d4b6");
416+
fn string(c: char) -> ~str {
417+
let mut result = ~"";
418+
do escape_unicode(c) |c| { result.push_char(c); }
419+
return result;
420+
}
421+
assert_eq!(string('\x00'), ~"\\x00");
422+
assert_eq!(string('\n'), ~"\\x0a");
423+
assert_eq!(string(' '), ~"\\x20");
424+
assert_eq!(string('a'), ~"\\x61");
425+
assert_eq!(string('\u011b'), ~"\\u011b");
426+
assert_eq!(string('\U0001d4b6'), ~"\\U0001d4b6");
418427
}

src/libstd/repr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ impl EscapedCharWriter for @Writer {
5757
'"' => self.write_str("\\\""),
5858
'\x20'..'\x7e' => self.write_char(ch),
5959
_ => {
60-
// FIXME #4423: This is inefficient because it requires a
61-
// malloc.
62-
self.write_str(char::escape_unicode(ch))
60+
do char::escape_unicode(ch) |c| {
61+
self.write_char(c);
62+
}
6363
}
6464
}
6565
}

src/libsyntax/parse/token.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use util::interner::StrInterner;
1616
use util::interner;
1717

1818
use std::cast;
19-
use std::char;
2019
use std::cmp::Equiv;
2120
use std::local_data;
2221
use std::rand;
@@ -166,7 +165,12 @@ pub fn to_str(in: @ident_interner, t: &Token) -> ~str {
166165

167166
/* Literals */
168167
LIT_INT(c, ast::ty_char) => {
169-
~"'" + char::escape_default(c as char) + "'"
168+
let mut res = ~"'";
169+
do (c as char).escape_default |c| {
170+
res.push_char(c);
171+
}
172+
res.push_char('\'');
173+
res
170174
}
171175
LIT_INT(i, t) => {
172176
i.to_str() + ast_util::int_ty_to_str(t)

src/libsyntax/print/pprust.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use print::pp::{breaks, consistent, inconsistent, eof};
2727
use print::pp;
2828
use print::pprust;
2929

30-
use std::char;
3130
use std::io;
3231
use std::u64;
3332
use std::uint;
@@ -2016,7 +2015,12 @@ pub fn print_literal(s: @ps, lit: @ast::lit) {
20162015
match lit.node {
20172016
ast::lit_str(st) => print_string(s, st),
20182017
ast::lit_int(ch, ast::ty_char) => {
2019-
word(s.s, ~"'" + char::escape_default(ch as char) + "'");
2018+
let mut res = ~"'";
2019+
do (ch as char).escape_default |c| {
2020+
res.push_char(c);
2021+
}
2022+
res.push_char('\'');
2023+
word(s.s, res);
20202024
}
20212025
ast::lit_int(i, t) => {
20222026
if i < 0_i64 {

0 commit comments

Comments
 (0)