Improve Text.toDisplayString (#5045) (#5598)

This commit is contained in:
GregoryTravis 2023-02-13 13:38:15 -05:00 committed by GitHub
parent 95c66baa3c
commit 99b9728995
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 13 deletions

View File

@ -193,19 +193,36 @@ public final class Text implements TruffleObject {
boolean allowSideEffects, boolean allowSideEffects,
@Cached("build()") @Cached.Shared("strings") ToJavaStringNode toJavaStringNode) { @Cached("build()") @Cached.Shared("strings") ToJavaStringNode toJavaStringNode) {
String str = toJavaStringNode.execute(this); String str = toJavaStringNode.execute(this);
// TODO This should be more extensible int len = str.length();
String replaced = int outputLength = len + 2; // Precise if there are no special characters.
str.replace("\\", "\\\\")
.replace("'", "\\'") // TODO This should be more extensible; while it's still a small fixed set,
.replace("\n", "\\n") // a switch is probably fastest (unconfirmed)
.replace("\t", "\\t")
.replace("\u0007", "\\a") StringBuffer strBuf = new StringBuffer(outputLength);
.replace("\u0008", "\\b")
.replace("\u000c", "\\f") strBuf.append('\'');
.replace("\r", "\\r")
.replace("\u000B", "\\v") for (int i = 0; i < len; ++i) {
.replace("\u001B", "\\e"); char c = str.charAt(i);
return "'" + replaced + "'"; switch (c) {
case '\\' -> strBuf.append("\\\\");
case '\'' -> strBuf.append("\\'");
case '\n' -> strBuf.append("\\n");
case '\t' -> strBuf.append("\\t");
case '\u0007' -> strBuf.append("\\a");
case '\u0008' -> strBuf.append("\\b");
case '\u000c' -> strBuf.append("\\f");
case '\r' -> strBuf.append("\\r");
case '\u000B' -> strBuf.append("\\v");
case '\u001B' -> strBuf.append("\\e");
default -> strBuf.append(c);
}
}
strBuf.append('\'');
return strBuf.toString();
} }
@ExportMessage @ExportMessage

View File

@ -0,0 +1,37 @@
from Standard.Base import all
from Standard.Test import Bench, Faker
# Benchmarks ##################################################################
cycle_character_template num character_templates =
character_templates.at (num % (character_templates.length))
bench =
## The `Text.pretty` benchmarks check both scenarios where the Texts are
short and very long. This is to verify that making a single pass over
the text is in fact faster than multiple passes.
bench_pretty suite_prefix =
faker = Faker.new
regular_characters = (Faker.upper_case_letters + Faker.lower_case_letters)
# Keep this up to date with the special characters in Text.java
special_characters = '\\\'\n\t\u{7}\u{8}\u{c}\r\u{b}\u{1b}'.char_vector
# 20% special, 80% regular
make_template length =
r = regular_characters
s = special_characters
Vector.new length ix-> cycle_character_template ix [r, r, s, s, r]
very_short_template = make_template 4
very_short_random = faker.string_value very_short_template
big_template = make_template 100000
big_random = faker.string_value big_template
Bench.measure (very_short_random.pretty) suite_prefix+" 4" 10 10
Bench.measure (big_random.pretty) suite_prefix+" 100000" 10 10
bench_pretty "Text.pretty"
main = bench