Skip to content

Commit 473c038

Browse files
toml: avoid second char[] allocation when stripping underscores from integer literals (#13)
Co-authored-by: jaipilot[bot] <273169020+jaipilot[bot]@users.noreply.github.com>
1 parent 6ce8d82 commit 473c038

2 files changed

Lines changed: 29 additions & 9 deletions

File tree

toml/src/main/java/tools/jackson/dataformat/toml/TomlParser.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,18 +327,17 @@ private JsonNode parseInt(int nextState) throws IOException {
327327

328328
for (int i = 0; i < length; i++) {
329329
if (buffer[start + i] == '_') {
330-
// slow path to remove underscores: copy in-place, skipping '_'
331-
char[] cleaned = new char[length];
332-
int pos = 0;
333-
for (int j = 0; j < length; j++) {
334-
char c = buffer[start + j];
330+
// slow path to remove underscores: compact into the already-owned
331+
// buffer itself (chars before the first '_' are already in place),
332+
// avoiding a second array allocation
333+
int pos = start + i;
334+
for (int j = pos + 1; j < start + length; j++) {
335+
char c = buffer[j];
335336
if (c != '_') {
336-
cleaned[pos++] = c;
337+
buffer[pos++] = c;
337338
}
338339
}
339-
buffer = cleaned;
340-
start = 0;
341-
length = pos;
340+
length = pos - start;
342341
break;
343342
}
344343
}

toml/src/test/java/tools/jackson/dataformat/toml/LongTokenTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,27 @@ public void integerTooLongHex() throws IOException {
8484
assertRadixIntegerRejected("0xa");
8585
}
8686

87+
@Test
88+
public void integerUnderscoreBufferGrowth() throws IOException {
89+
// Digits interleaved with underscores, long enough to force the lexer's
90+
// token buffer (initial size 4000) to grow while removing the underscores,
91+
// followed by another key/value pair to prove later tokens are unaffected.
92+
StringBuilder digits = new StringBuilder();
93+
for (int i = 0; i < SCALE; i++) {
94+
digits.append((char) ('0' + (i % 10)));
95+
if (i % 3 == 2 && i != SCALE - 1) {
96+
digits.append('_');
97+
}
98+
}
99+
String toml = "foo = 1" + digits + "\nbar = 42";
100+
101+
ObjectNode node = (ObjectNode) NO_LIMITS_MAPPER.readTree(toml);
102+
103+
BigInteger expected = new BigInteger("1" + digits.toString().replace("_", ""));
104+
assertEquals(expected, node.get("foo").bigIntegerValue());
105+
assertEquals(42, node.get("bar").intValue());
106+
}
107+
87108
private void assertRadixIntegerRejected(String prefixAndFirstDigit) throws IOException {
88109
final ObjectMapper mapper = newTomlMapper();
89110
StringBuilder toml = new StringBuilder("foo = ").append(prefixAndFirstDigit);

0 commit comments

Comments
 (0)