From 4a51f26be29c1e816f26e5fbcd1ada5e1d2433c8 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Sat, 3 Oct 2026 21:47:10 +0300 Subject: [PATCH] Cache the indentation strings of the output lines Every output line's indentation was a fresh `" ".repeat(indent)`. JavaOutput.spaces(int) now hands out one String per width up to 100 spaces, built on first use; wider widths are built as before, and zero or less gives the empty string. Taken from google/google-java-format#1466 (Liam Miller-Cushon), minus its Style.indentString half, which has no counterpart here: the fork's Style knows no tabs, and JavaOutput.indent is the only caller. JavaOutputTest asks for the same instance twice, for the empty string at zero and below, and for a width beyond the cache. Measured on the 135 files of java.util from JDK 21, six passes on one thread, bytes from ThreadMXBean.getThreadAllocatedBytes: 1,980 MB per pass before, 1,977 MB after, about 30 bytes per output line out of 17,770. The time per pass does not move, and the JDK 21 sources format exactly as before. --- .../palantir/javaformat/java/JavaOutput.java | 21 ++++++++- .../javaformat/java/JavaOutputTest.java | 43 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 open-java-format/src/test/java/com/palantir/javaformat/java/JavaOutputTest.java diff --git a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java index 36b015bc2..96bdc3a8e 100644 --- a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java +++ b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java @@ -56,6 +56,25 @@ public final class JavaOutput extends Output { // never ends in whitespace: trailing tabs inside a comment were kept before, and only a second run removed them. private StringBuilder spacesPending = new StringBuilder(); + private static final int MAX_CACHED_SPACES = 100; + private static final String[] SPACES = new String[MAX_CACHED_SPACES + 1]; + + /** Returns an indentation string of the given number of spaces. */ + static String spaces(int indent) { + if (indent <= 0) { + return ""; + } + if (indent <= MAX_CACHED_SPACES) { + String result = SPACES[indent]; + if (result == null) { + result = " ".repeat(indent); + SPACES[indent] = result; + } + return result; + } + return " ".repeat(indent); + } + /** * {@code JavaOutput} constructor. * @@ -157,7 +176,7 @@ public void append(State state, String text, Range range) { @Override public void indent(int indent) { - spacesPending.append(" ".repeat(indent)); + spacesPending.append(spaces(indent)); } /** Flush any incomplete last line, then add the EOF token into our data structures. */ diff --git a/open-java-format/src/test/java/com/palantir/javaformat/java/JavaOutputTest.java b/open-java-format/src/test/java/com/palantir/javaformat/java/JavaOutputTest.java new file mode 100644 index 000000000..cc144b53d --- /dev/null +++ b/open-java-format/src/test/java/com/palantir/javaformat/java/JavaOutputTest.java @@ -0,0 +1,43 @@ +/* + * (c) Copyright 2026 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.javaformat.java; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +final class JavaOutputTest { + + @Test + void cachesTheIndentationStrings() { + // Every output line used to get a fresh `" ".repeat(indent)`; the usual widths now come from a cache. + assertThat(JavaOutput.spaces(4)).isEqualTo(" "); + assertThat(JavaOutput.spaces(4)).isSameAs(JavaOutput.spaces(4)); + assertThat(JavaOutput.spaces(100)).isSameAs(JavaOutput.spaces(100)); + } + + @Test + void returnsNoSpacesForZeroOrLess() { + assertThat(JavaOutput.spaces(0)).isEmpty(); + assertThat(JavaOutput.spaces(-1)).isEmpty(); + } + + @Test + void buildsWidthsBeyondTheCache() { + assertThat(JavaOutput.spaces(104)).isEqualTo(" ".repeat(104)); + } +}