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,
@Cached("build()") @Cached.Shared("strings") ToJavaStringNode toJavaStringNode) {
String str = toJavaStringNode.execute(this);
// TODO This should be more extensible
String replaced =
str.replace("\\", "\\\\")
.replace("'", "\\'")
.replace("\n", "\\n")
.replace("\t", "\\t")
.replace("\u0007", "\\a")
.replace("\u0008", "\\b")
.replace("\u000c", "\\f")
.replace("\r", "\\r")
.replace("\u000B", "\\v")
.replace("\u001B", "\\e");
return "'" + replaced + "'";
int len = str.length();
int outputLength = len + 2; // Precise if there are no special characters.
// TODO This should be more extensible; while it's still a small fixed set,
// a switch is probably fastest (unconfirmed)
StringBuffer strBuf = new StringBuffer(outputLength);
strBuf.append('\'');
for (int i = 0; i < len; ++i) {
char c = str.charAt(i);
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

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