Skip to content

Commit ea246eb

Browse files
committed
SmileGenerator: avoid String allocation
1 parent 5463350 commit ea246eb

1 file changed

Lines changed: 45 additions & 2 deletions

File tree

smile/src/main/java/tools/jackson/dataformat/smile/SmileGenerator.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -932,9 +932,14 @@ private final void _writeNonSharedString(final String text, final int len) throw
932932
@Override
933933
public JsonGenerator writeString(char[] text, int offset, int len) throws JacksonException
934934
{
935-
// Shared strings are tricky; easiest to just construct String, call the other method
935+
// Shared strings: try char-array lookup first to avoid String allocation
936936
if (len <= MAX_SHARED_STRING_LENGTH_BYTES && _seenStringValueCount >= 0 && len > 0) {
937-
return writeString(new String(text, offset, len));
937+
int ix = _findSeenStringValue(text, offset, len);
938+
if (ix >= 0) {
939+
_verifyValueWrite("write String value");
940+
_writeSharedStringValueReference(ix);
941+
return this;
942+
}
938943
}
939944
_verifyValueWrite("write String value");
940945
if (len == 0) {
@@ -984,6 +989,10 @@ public JsonGenerator writeString(char[] text, int offset, int len) throws Jackso
984989
_writeByte(BYTE_MARKER_END_OF_STRING);
985990
}
986991
}
992+
// Only allocate String here if we need to store for shared-value tracking
993+
if (len <= MAX_SHARED_STRING_LENGTH_BYTES && _seenStringValueCount >= 0) {
994+
_addSeenStringValue(new String(text, offset, len));
995+
}
987996
return this;
988997
}
989998

@@ -2590,6 +2599,40 @@ private final int _findSeenStringValue(String text)
25902599
return -1;
25912600
}
25922601

2602+
/**
2603+
* Lookup variant that works directly on a char array, avoiding the need
2604+
* to allocate a {@link String} just for the shared-value check.
2605+
*/
2606+
private final int _findSeenStringValue(char[] text, int offset, int len)
2607+
{
2608+
// Compute hash the same way String.hashCode does
2609+
int hash = 0;
2610+
for (int i = offset, end = offset + len; i < end; ++i) {
2611+
hash = 31 * hash + text[i];
2612+
}
2613+
SharedStringNode head = _seenStringValues[hash & (_seenStringValues.length-1)];
2614+
if (head != null) {
2615+
SharedStringNode node = head;
2616+
do {
2617+
String value = node.value;
2618+
if (value.length() == len && value.hashCode() == hash) {
2619+
boolean match = true;
2620+
for (int i = 0; i < len; ++i) {
2621+
if (value.charAt(i) != text[offset + i]) {
2622+
match = false;
2623+
break;
2624+
}
2625+
}
2626+
if (match) {
2627+
return node.index;
2628+
}
2629+
}
2630+
node = node.next;
2631+
} while (node != null);
2632+
}
2633+
return -1;
2634+
}
2635+
25932636
private final void _addSeenStringValue(String text)
25942637
{
25952638
// first: do we need to expand?

0 commit comments

Comments
 (0)