61
61
*
62
62
* @author Arjen Poutsma
63
63
* @author Brian Clozel
64
+ * @author Nabil Fawwaz Elqayyim
64
65
* @since 5.0
65
66
*/
66
67
public abstract class DataBufferUtils {
@@ -859,23 +860,17 @@ public void reset() {
859
860
860
861
861
862
/**
862
- * An abstract base implementation of {@link NestedMatcher} that looks for
863
- * a specific delimiter in a {@link DataBuffer}.
864
- * <p>
865
- * Uses a thread-local buffer to scan data in chunks, reducing memory
866
- * allocations and improving performance when processing large buffers.
867
- * </p>
863
+ * Base {@link NestedMatcher} implementation that scans a {@link DataBuffer}
864
+ * for a specific delimiter.
868
865
*
869
- * <p>
870
- * Each matcher keeps its own match state, so it is intended for
871
- * single-threaded use. The thread-local buffer ensures that multiple
872
- * threads can run their own matchers independently without interfering.
873
- * </p>
866
+ * <p>Relies on a per-instance reusable buffer to scan data in chunks,
867
+ * minimizing allocations and improving performance for large or streaming data.</p>
874
868
*
875
- * <p>
876
- * Subclasses can extend this class to add custom matching behavior while
877
- * reusing the built-in delimiter tracking and scanning logic.
878
- * </p>
869
+ * <p>Each matcher maintains its own state and buffer, ensuring safe use
870
+ * in reactive pipelines where execution may shift across threads.</p>
871
+ *
872
+ * <p>Subclasses may extend this class to customize matching strategies
873
+ * while reusing the built-in delimiter tracking and scanning logic.</p>
879
874
*
880
875
* @see NestedMatcher
881
876
* @see DataBuffer
@@ -886,8 +881,7 @@ private abstract static class AbstractNestedMatcher implements NestedMatcher {
886
881
887
882
private int matches = 0 ;
888
883
889
- // Thread-local chunk buffer to avoid per-call allocations
890
- private static final ThreadLocal <byte []> LOCAL_BUFFER = ThreadLocal .withInitial (() -> new byte [8 * 1024 ]);
884
+ private final byte [] localBuffer = new byte [8 * 1024 ]; // Reusable buffer per matcher instance
891
885
892
886
protected AbstractNestedMatcher (byte [] delimiter ) {
893
887
this .delimiter = delimiter ;
@@ -901,33 +895,29 @@ protected int getMatches() {
901
895
return this .matches ;
902
896
}
903
897
904
- protected static void releaseLocalBuffer () {
905
- LOCAL_BUFFER .remove ();
906
- }
907
-
908
898
@ Override
909
899
public int match (DataBuffer dataBuffer ) {
910
900
final int readPos = dataBuffer .readPosition ();
911
901
final int writePos = dataBuffer .writePosition ();
912
902
final int length = writePos - readPos ;
913
903
914
- final byte [] delimiter0 = this .delimiter ;
915
- final int delimiterLen = delimiter0 .length ;
916
- final byte delimiter1 = delimiter0 [0 ];
904
+ final byte [] delimiterBytes = this .delimiter ;
905
+ final int delimiterLength = delimiterBytes .length ;
906
+ final byte delimiterFirstByte = delimiterBytes [0 ];
917
907
918
- int matchIndex = this .matches ;
919
-
920
- final byte [] chunk = LOCAL_BUFFER .get ();
908
+ final byte [] chunk = localBuffer ;
921
909
final int chunkSize = Math .min (chunk .length , length );
922
910
911
+ int matchIndex = this .matches ;
912
+
923
913
try {
924
914
for (int offset = 0 ; offset < length ; offset += chunkSize ) {
925
915
int currentChunkSize = Math .min (chunkSize , length - offset );
926
916
927
917
dataBuffer .readPosition (readPos + offset );
928
918
dataBuffer .read (chunk , 0 , currentChunkSize );
929
919
930
- matchIndex = processChunk (chunk , currentChunkSize , delimiter0 , delimiterLen , delimiter1 , matchIndex , readPos , offset );
920
+ matchIndex = processChunk (chunk , currentChunkSize , delimiterBytes , delimiterLength , delimiterFirstByte , matchIndex , readPos , offset );
931
921
if (matchIndex < 0 ) {
932
922
return -(matchIndex + 1 ); // found, returning actual position
933
923
}
@@ -938,21 +928,20 @@ public int match(DataBuffer dataBuffer) {
938
928
}
939
929
finally {
940
930
dataBuffer .readPosition (readPos ); // restore original position
941
- releaseLocalBuffer ();
942
931
}
943
932
}
944
933
945
- private int processChunk (byte [] chunk , int currentChunkSize , byte [] delimiter0 , int delimiterLen , byte delimiter1 , int matchIndex , int readPos , int offset ) {
934
+ private int processChunk (byte [] chunk , int currentChunkSize , byte [] delimiterBytes , int delimiterLen , byte delimiterFirstByte , int matchIndex , int readPos , int offset ) {
946
935
int i = 0 ;
947
936
while (i < currentChunkSize ) {
948
937
if (matchIndex == 0 ) {
949
- i = findNextCandidate (chunk , i , currentChunkSize , delimiter1 );
938
+ i = findNextCandidate (chunk , i , currentChunkSize , delimiterFirstByte );
950
939
if (i >= currentChunkSize ) {
951
940
return matchIndex ; // no candidate in this chunk
952
941
}
953
942
}
954
943
955
- matchIndex = updateMatchIndex (chunk [i ], delimiter0 , delimiterLen , delimiter1 , matchIndex );
944
+ matchIndex = updateMatchIndex (chunk [i ], delimiterBytes , delimiterLen , delimiterFirstByte , matchIndex );
956
945
if (matchIndex == -1 ) {
957
946
return -(readPos + offset + i + 1 ); // return found delimiter position (encoded as negative)
958
947
}
@@ -961,24 +950,24 @@ private int processChunk(byte[] chunk, int currentChunkSize, byte[] delimiter0,
961
950
return matchIndex ;
962
951
}
963
952
964
- private int findNextCandidate (byte [] chunk , int start , int limit , byte delimiter1 ) {
953
+ private int findNextCandidate (byte [] chunk , int start , int limit , byte delimiterFirstByte ) {
965
954
int j = start ;
966
- while (j < limit && chunk [j ] != delimiter1 ) {
955
+ while (j < limit && chunk [j ] != delimiterFirstByte ) {
967
956
j ++;
968
957
}
969
958
return j ;
970
959
}
971
960
972
- private int updateMatchIndex (byte b , byte [] delimiter0 , int delimiterLen , byte delimiter1 , int matchIndex ) {
973
- if (b == delimiter0 [matchIndex ]) {
961
+ private int updateMatchIndex (byte b , byte [] delimiterBytes , int delimiterLen , byte delimiterFirstByte , int matchIndex ) {
962
+ if (b == delimiterBytes [matchIndex ]) {
974
963
matchIndex ++;
975
964
if (matchIndex == delimiterLen ) {
976
965
reset ();
977
966
return -1 ;
978
967
}
979
968
}
980
969
else {
981
- matchIndex = (b == delimiter1 ) ? 1 : 0 ;
970
+ matchIndex = (b == delimiterFirstByte ) ? 1 : 0 ;
982
971
}
983
972
return matchIndex ;
984
973
}
0 commit comments