Auto merge of #121150 - Swatinem:debug-ascii-str, r=joboet
Add a fast-path to `Debug` ASCII `&str` Instead of going through the `EscapeDebug` machinery, we can just skip over ASCII chars that don’t need any escaping. --- This is an alternative / a companion to https://github.com/rust-lang/rust/pull/121138. The other PR is adding the fast path deep within `EscapeDebug`, whereas this skips as early as possible.
This commit is contained in:
commit
213ad10c8f
@ -44,7 +44,7 @@ fn ascii_escapes(b: &mut Bencher) {
|
|||||||
assert_fmt(
|
assert_fmt(
|
||||||
s,
|
s,
|
||||||
r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#,
|
r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#,
|
||||||
21,
|
15,
|
||||||
);
|
);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
black_box(format!("{:?}", black_box(s)));
|
black_box(format!("{:?}", black_box(s)));
|
||||||
@ -72,7 +72,7 @@ fn mostly_unicode(b: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn mixed(b: &mut Bencher) {
|
fn mixed(b: &mut Bencher) {
|
||||||
let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\".";
|
let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\".";
|
||||||
assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 36);
|
assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 21);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
black_box(format!("{:?}", black_box(s)));
|
black_box(format!("{:?}", black_box(s)));
|
||||||
});
|
});
|
||||||
|
@ -2402,23 +2402,47 @@ impl Display for bool {
|
|||||||
impl Debug for str {
|
impl Debug for str {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
f.write_char('"')?;
|
f.write_char('"')?;
|
||||||
let mut from = 0;
|
|
||||||
for (i, c) in self.char_indices() {
|
// substring we know is printable
|
||||||
let esc = c.escape_debug_ext(EscapeDebugExtArgs {
|
let mut printable_range = 0..0;
|
||||||
escape_grapheme_extended: true,
|
|
||||||
escape_single_quote: false,
|
fn needs_escape(b: u8) -> bool {
|
||||||
escape_double_quote: true,
|
b > 0x7E || b < 0x20 || b == b'\\' || b == b'"'
|
||||||
});
|
|
||||||
// If char needs escaping, flush backlog so far and write, else skip
|
|
||||||
if esc.len() != 1 {
|
|
||||||
f.write_str(&self[from..i])?;
|
|
||||||
for c in esc {
|
|
||||||
f.write_char(c)?;
|
|
||||||
}
|
|
||||||
from = i + c.len_utf8();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
f.write_str(&self[from..])?;
|
|
||||||
|
// the loop here first skips over runs of printable ASCII as a fast path.
|
||||||
|
// other chars (unicode, or ASCII that needs escaping) are then handled per-`char`.
|
||||||
|
let mut rest = self;
|
||||||
|
while rest.len() > 0 {
|
||||||
|
let Some(non_printable_start) = rest.as_bytes().iter().position(|&b| needs_escape(b))
|
||||||
|
else {
|
||||||
|
printable_range.end += rest.len();
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
printable_range.end += non_printable_start;
|
||||||
|
// SAFETY: the position was derived from an iterator, so is known to be within bounds, and at a char boundary
|
||||||
|
rest = unsafe { rest.get_unchecked(non_printable_start..) };
|
||||||
|
|
||||||
|
let mut chars = rest.chars();
|
||||||
|
if let Some(c) = chars.next() {
|
||||||
|
let esc = c.escape_debug_ext(EscapeDebugExtArgs {
|
||||||
|
escape_grapheme_extended: true,
|
||||||
|
escape_single_quote: false,
|
||||||
|
escape_double_quote: true,
|
||||||
|
});
|
||||||
|
if esc.len() != 1 {
|
||||||
|
f.write_str(&self[printable_range.clone()])?;
|
||||||
|
Display::fmt(&esc, f)?;
|
||||||
|
printable_range.start = printable_range.end + c.len_utf8();
|
||||||
|
}
|
||||||
|
printable_range.end += c.len_utf8();
|
||||||
|
}
|
||||||
|
rest = chars.as_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_str(&self[printable_range])?;
|
||||||
|
|
||||||
f.write_char('"')
|
f.write_char('"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2434,13 +2458,12 @@ impl Display for str {
|
|||||||
impl Debug for char {
|
impl Debug for char {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
f.write_char('\'')?;
|
f.write_char('\'')?;
|
||||||
for c in self.escape_debug_ext(EscapeDebugExtArgs {
|
let esc = self.escape_debug_ext(EscapeDebugExtArgs {
|
||||||
escape_grapheme_extended: true,
|
escape_grapheme_extended: true,
|
||||||
escape_single_quote: true,
|
escape_single_quote: true,
|
||||||
escape_double_quote: false,
|
escape_double_quote: false,
|
||||||
}) {
|
});
|
||||||
f.write_char(c)?
|
Display::fmt(&esc, f)?;
|
||||||
}
|
|
||||||
f.write_char('\'')
|
f.write_char('\'')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user