From 86338266807cb8d78082179733b31a8fd0be972c Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 4 Apr 2025 14:10:48 -0700 Subject: [PATCH] Optimize string wrapping PiperOrigin-RevId: 744065507 --- .../googlejavaformat/java/StringWrapper.java | 36 ++++++---- .../java/StringWrapperIntegrationTest.java | 65 +++++++++++++++++++ 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java index 27450d82f..f1014e52f 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -53,7 +53,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Stream; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.DiagnosticListener; @@ -316,19 +315,21 @@ private static ImmutableList stringComponents( } static int hasEscapedWhitespaceAt(String input, int idx) { - return Stream.of("\\t") - .mapToInt(x -> input.startsWith(x, idx) ? x.length() : -1) - .filter(x -> x != -1) - .findFirst() - .orElse(-1); + if (input.startsWith("\\t", idx)) { + return 2; + } + return -1; } static int hasEscapedNewlineAt(String input, int idx) { - return Stream.of("\\r\\n", "\\r", "\\n") - .mapToInt(x -> input.startsWith(x, idx) ? x.length() : -1) - .filter(x -> x != -1) - .findFirst() - .orElse(-1); + int offset = 0; + if (input.startsWith("\\r", idx)) { + offset += 2; + } + if (input.startsWith("\\n", idx)) { + offset += 2; + } + return offset > 0 ? offset : -1; } /** @@ -360,7 +361,7 @@ private static String reflow( List line = new ArrayList<>(); // If we know this is going to be the last line, then remove a bit of width to account for the // trailing characters. - if (input.stream().mapToInt(String::length).sum() <= width) { + if (totalLengthLessThanOrEqual(input, width)) { // This isn’t quite optimal, but arguably good enough. See b/179561701 width -= trailing; } @@ -391,6 +392,17 @@ private static String reflow( "\"")); } + private static boolean totalLengthLessThanOrEqual(Iterable input, int length) { + int total = 0; + for (String s : input) { + total += s.length(); + if (total > length) { + return false; + } + } + return true; + } + /** * Flattens the given binary expression tree, and extracts the subset that contains the given path * and any adjacent nodes that are also string literals. diff --git a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperIntegrationTest.java b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperIntegrationTest.java index 53fb54d91..5032ac97c 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperIntegrationTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperIntegrationTest.java @@ -365,6 +365,71 @@ public static Collection parameters() { "}" }, }, + { + { + "class T {", // + " String s = \"\\r\\rone\\rlong\\rincredibly\\runbroken\\rsentence\\rmoving\\rfrom\\r" + + " topic\\rto\\r topic\\rso\\rthat\\rno-one\\rhad\\ra\\rchance\\rto\\rinterrupt\";", + "}" + }, + { + "class T {", + " String s =", + " \"\\r\\r\"", + " + \"one\\r\"", + " + \"long\\r\"", + " + \"incredibly\\r\"", + " + \"unbroken\\r\"", + " + \"sentence\\r\"", + " + \"moving\\r\"", + " + \"from\\r\"", + " + \" topic\\r\"", + " + \"to\\r\"", + " + \" topic\\r\"", + " + \"so\\r\"", + " + \"that\\r\"", + " + \"no-one\\r\"", + " + \"had\\r\"", + " + \"a\\r\"", + " + \"chance\\r\"", + " + \"to\\r\"", + " + \"interrupt\";", + "}", + }, + }, + { + { + "class T {", // + " String s = \"\\r\\n\\r\\none\\r\\nlong\\r\\nincredibly\\r\\nunbroken\\r\\nsentence" + + "\\r\\nmoving\\r\\nfrom\\r\\n topic\\r\\nto\\r\\n topic\\r\\nso\\r\\nthat\\r\\n" + + "no-one\\r\\nhad\\r\\na\\r\\nchance\\r\\nto\\r\\ninterrupt\";", + "}" + }, + { + "class T {", + " String s =", + " \"\\r\\n\\r\\n\"", + " + \"one\\r\\n\"", + " + \"long\\r\\n\"", + " + \"incredibly\\r\\n\"", + " + \"unbroken\\r\\n\"", + " + \"sentence\\r\\n\"", + " + \"moving\\r\\n\"", + " + \"from\\r\\n\"", + " + \" topic\\r\\n\"", + " + \"to\\r\\n\"", + " + \" topic\\r\\n\"", + " + \"so\\r\\n\"", + " + \"that\\r\\n\"", + " + \"no-one\\r\\n\"", + " + \"had\\r\\n\"", + " + \"a\\r\\n\"", + " + \"chance\\r\\n\"", + " + \"to\\r\\n\"", + " + \"interrupt\";", + "}", + }, + }, }; return Arrays.stream(inputsAndOutputs) .map(