|
11 | 11 | import java.util.Deque; |
12 | 12 | import java.util.HashMap; |
13 | 13 | import java.util.Iterator; |
| 14 | +import java.util.LinkedHashMap; |
14 | 15 | import java.util.List; |
15 | 16 | import java.util.Map; |
16 | 17 | import java.util.Objects; |
@@ -621,7 +622,7 @@ public abstract class AbstractCodeWriter<T extends AbstractCodeWriter<T>> { |
621 | 622 | private boolean trailingNewline = true; |
622 | 623 | private int trimBlankLines = -1; |
623 | 624 | private boolean enableStackTraceComments; |
624 | | - private final Map<String, Supplier<String>> deferredValues = new HashMap<>(); |
| 625 | + private final Map<String, Supplier<String>> deferredValues = new LinkedHashMap<>(); |
625 | 626 | private int deferredCounter = 0; |
626 | 627 |
|
627 | 628 | /** |
@@ -789,8 +790,33 @@ public String toString() { |
789 | 790 |
|
790 | 791 | // Resolve any deferred values. |
791 | 792 | 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; |
792 | 796 | 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(); |
794 | 820 | } |
795 | 821 | } |
796 | 822 |
|
|
0 commit comments