Skip to content

Commit 813ac53

Browse files
committed
Optimize deferred render to do a single input scan and use a single output buffer
1 parent 5bddafa commit 813ac53

1 file changed

Lines changed: 28 additions & 2 deletions

File tree

smithy-utils/src/main/java/software/amazon/smithy/utils/AbstractCodeWriter.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Deque;
1212
import java.util.HashMap;
1313
import java.util.Iterator;
14+
import java.util.LinkedHashMap;
1415
import java.util.List;
1516
import java.util.Map;
1617
import java.util.Objects;
@@ -621,7 +622,7 @@ public abstract class AbstractCodeWriter<T extends AbstractCodeWriter<T>> {
621622
private boolean trailingNewline = true;
622623
private int trimBlankLines = -1;
623624
private boolean enableStackTraceComments;
624-
private final Map<String, Supplier<String>> deferredValues = new HashMap<>();
625+
private final Map<String, Supplier<String>> deferredValues = new LinkedHashMap<>();
625626
private int deferredCounter = 0;
626627

627628
/**
@@ -789,8 +790,33 @@ public String toString() {
789790

790791
// Resolve any deferred values.
791792
if (!deferredValues.isEmpty()) {
793+
// Find all sentinel positions, then resolve in a single linear pass.
794+
List<int[]> positions = new ArrayList<>();
795+
int idx = 0;
792796
for (Map.Entry<String, Supplier<String>> entry : deferredValues.entrySet()) {
793-
result = result.replace(entry.getKey(), entry.getValue().get());
797+
String key = entry.getKey();
798+
int fromIndex = 0;
799+
while ((fromIndex = result.indexOf(key, fromIndex)) != -1) {
800+
// Store [position, index-into-entries-list, key-length]
801+
positions.add(new int[]{fromIndex, idx, key.length()});
802+
fromIndex += key.length();
803+
}
804+
idx++;
805+
}
806+
if (!positions.isEmpty()) {
807+
positions.sort((a, b) -> Integer.compare(a[0], b[0]));
808+
// Build list of suppliers indexed by insertion order for O(1) lookup.
809+
@SuppressWarnings("unchecked")
810+
Supplier<String>[] suppliers = deferredValues.values().toArray(new Supplier[0]);
811+
StringBuilder resolved = new StringBuilder(result.length());
812+
int pos = 0;
813+
for (int[] entry : positions) {
814+
resolved.append(result, pos, entry[0]);
815+
resolved.append(suppliers[entry[1]].get());
816+
pos = entry[0] + entry[2];
817+
}
818+
resolved.append(result, pos, result.length());
819+
result = resolved.toString();
794820
}
795821
}
796822

0 commit comments

Comments
 (0)