11package org .simdjson ;
22
3- import jdk .incubator .vector .ByteVector ;
4-
53import java .util .Arrays ;
64
7- import static org .simdjson .JsonCharUtils .isStructuralOrWhitespace ;
5+ import static org .simdjson .CharacterUtils .isStructuralOrWhitespace ;
86import static org .simdjson .Tape .END_ARRAY ;
97import static org .simdjson .Tape .END_OBJECT ;
108import static org .simdjson .Tape .FALSE_VALUE ;
119import static org .simdjson .Tape .NULL_VALUE ;
1210import static org .simdjson .Tape .ROOT ;
1311import static org .simdjson .Tape .START_ARRAY ;
1412import static org .simdjson .Tape .START_OBJECT ;
15- import static org .simdjson .Tape .STRING ;
1613import static org .simdjson .Tape .TRUE_VALUE ;
1714
1815class TapeBuilder {
1916
2017 private static final byte SPACE = 0x20 ;
21- private static final byte BACKSLASH = '\\' ;
22- private static final byte QUOTE = '"' ;
23- private static final int BYTES_PROCESSED = StructuralIndexer .SPECIES .vectorByteSize ();
24- private static final byte [] ESCAPE_MAP = new byte []{
25- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x0.
26- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
27- 0 , 0 , 0x22 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2f ,
28- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
29-
30- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x4.
31- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5c , 0 , 0 , 0 , // 0x5.
32- 0 , 0 , 0x08 , 0 , 0 , 0 , 0x0c , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0a , 0 , // 0x6.
33- 0 , 0 , 0x0d , 0 , 0x09 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0x7.
34-
35- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
36- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
37- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
38- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
39-
40- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
41- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
42- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
43- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
44- };
4518
4619 private final Tape tape ;
4720 private final byte [] stringBuffer ;
4821 private final OpenContainer [] openContainers ;
4922 private final int padding ;
5023 private final NumberParser numberParser ;
51-
52- private int stringBufferIdx ;
24+ private final StringParser stringParser ;
5325
5426 TapeBuilder (int capacity , int depth , int padding ) {
5527 this .tape = new Tape (capacity );
@@ -60,6 +32,7 @@ class TapeBuilder {
6032 }
6133 this .stringBuffer = new byte [capacity ];
6234 this .numberParser = new NumberParser (tape );
35+ this .stringParser = new StringParser (tape , stringBuffer );
6336 }
6437
6538 void visitDocumentStart () {
@@ -193,56 +166,7 @@ void visitKey(byte[] buffer, int idx) {
193166 }
194167
195168 private void visitString (byte [] buffer , int idx ) {
196- tape .append (stringBufferIdx , STRING );
197- int src = idx + 1 ;
198- int dst = stringBufferIdx + Integer .BYTES ;
199- while (true ) {
200- ByteVector srcVec = ByteVector .fromArray (StructuralIndexer .SPECIES , buffer , src );
201- srcVec .intoArray (stringBuffer , dst );
202- long backslashBits = srcVec .eq (BACKSLASH ).toLong ();
203- long quoteBits = srcVec .eq (QUOTE ).toLong ();
204-
205- if (hasQuoteFirst (backslashBits , quoteBits )) {
206- dst += Long .numberOfTrailingZeros (quoteBits );
207- break ;
208- }
209- if (hasBackslash (backslashBits , quoteBits )) {
210- int backslashDist = Long .numberOfTrailingZeros (backslashBits );
211- byte escapeChar = buffer [src + backslashDist + 1 ];
212- if (escapeChar == 'u' ) {
213- throw new UnsupportedOperationException ("Support for unicode characters is not implemented yet." );
214- } else {
215- stringBuffer [dst + backslashDist ] = escape (escapeChar );
216- src += backslashDist + 2 ;
217- dst += backslashDist + 1 ;
218- }
219- } else {
220- src += BYTES_PROCESSED ;
221- dst += BYTES_PROCESSED ;
222- }
223- }
224- int len = dst - stringBufferIdx - Integer .BYTES ;
225- IntegerUtils .toBytes (len , stringBuffer , stringBufferIdx );
226- stringBufferIdx = dst ;
227- }
228-
229- private byte escape (byte escapeChar ) {
230- if (escapeChar < 0 ) {
231- throw new JsonParsingException ("Escaped unexpected character: " + ((char ) escapeChar ));
232- }
233- byte escapeResult = ESCAPE_MAP [escapeChar ];
234- if (escapeResult == 0 ) {
235- throw new JsonParsingException ("Escaped unexpected character: " + ((char ) escapeChar ));
236- }
237- return escapeResult ;
238- }
239-
240- private boolean hasQuoteFirst (long backslashBits , long quoteBits ) {
241- return ((backslashBits - 1 ) & quoteBits ) != 0 ;
242- }
243-
244- private boolean hasBackslash (long backslashBits , long quoteBits ) {
245- return ((quoteBits - 1 ) & backslashBits ) != 0 ;
169+ stringParser .parseString (buffer , idx );
246170 }
247171
248172 private void visitNumber (byte [] buffer , int idx ) {
@@ -278,7 +202,7 @@ private void emptyContainer(char start, char end) {
278202
279203 void reset () {
280204 tape .reset ();
281- stringBufferIdx = 0 ;
205+ stringParser . reset () ;
282206 }
283207
284208 JsonValue createJsonValue (byte [] buffer ) {
0 commit comments