@@ -175,16 +175,20 @@ size_t hw_json_simd_write_bp_chunk(
175175
176176 size_t pc_ib = __builtin_popcountll (w64_ib );
177177
178+ // Ignoring non interesting bits, get a bitmask of all delimiters and
179+ // opens and closes.
178180 uint64_t ext_d = _pext_u64 (~(w64_a | w64_z ) , w64_ib );
179181 uint64_t ext_a = _pext_u64 (w64_a , w64_ib );
180182 uint64_t ext_z = _pext_u64 (w64_z , w64_ib );
181183
184+ // Merge with the remainder bits. Extract bits need to be shifted
185+ // to avoid cloberring the remainder bits.
182186 remainder_bits_d |= (ext_d << remainder_len );
183187 remainder_bits_a |= (ext_a << remainder_len );
184188 remainder_bits_z |= (ext_z << remainder_len );
185189
186190 if (remainder_len + pc_ib >= 64 ) {
187- // Write full word
191+ // Write full word because we have enough bits
188192 w64_work_bp [w64s_ready ] =
189193 _pdep_u64 (remainder_bits_a , 0x5555555555555555 ) |
190194 _pdep_u64 (remainder_bits_a , 0xaaaaaaaaaaaaaaaa ) |
@@ -203,7 +207,7 @@ size_t hw_json_simd_write_bp_chunk(
203207
204208 w64s_ready += 1 ;
205209
206- // Set up for next iteration
210+ // Set up for next iteration the bits that didn't fit
207211 remainder_bits_d = ext_d >> (64 - remainder_len );
208212 remainder_bits_a = ext_a >> (64 - remainder_len );
209213 remainder_bits_z = ext_z >> (64 - remainder_len );
@@ -291,13 +295,20 @@ uint8_t hw_json_simd_escape_mask[2][256] =
291295 }
292296 };
293297
298+ // Summarise the input buffer into masks that indicate characters that have bearing on how the
299+ // JSON fragment is structured. Of these only ":,{}[]" are candidates to be interesting-bits.
300+ // However, not every such occurence is an interesting-bit because they may be inside a string
301+ // literal. What makes this more complicated is that the string literal may itself contain
302+ // escaped characters.
303+ // This function generates the masks for the characters of interest so that a later stage may
304+ // using them to determine the interesting-bits.
294305void hw_json_simd_summarise (
295- uint8_t * buffer ,
296- uint32_t * out_mask_d ,
297- uint32_t * out_mask_a ,
298- uint32_t * out_mask_z ,
299- uint32_t * out_mask_q ,
300- uint32_t * out_mask_b ) {
306+ uint8_t * buffer , // Input buffer of 32 bytes containing a JSON fragment
307+ uint32_t * out_mask_d , // Output buffer for receiving the mask for delimiter characters: ':,'
308+ uint32_t * out_mask_a , // Output buffer for receiving the mask of the opening character: '{['
309+ uint32_t * out_mask_z , // Output buffer for receiving the mask of the closing character: ']}'
310+ uint32_t * out_mask_q , // Output buffer for receiving the mask of the quote character: '"'
311+ uint32_t * out_mask_b ) { // Output buffer for receiving the mask of the backslash character: '\'
301312#ifdef __AVX2__
302313 __m256i v_in_data = * (__m256i * )buffer ;
303314 __m256i v_bytes_of_comma = _mm256_cmpeq_epi8 (v_in_data , _mm256_set1_epi8 (',' ));
@@ -344,6 +355,11 @@ void hw_json_simd_summarise(
344355#endif
345356}
346357
358+ // Add two words 'a' and 'b' and a carry bit 'c' together.
359+ // Detect this three-way addition overflow and set the carry bit accordingly in 'c'.
360+ // A utility function that can be used to add two arbitrary bit strings of the same length together.
361+ // The function itself doesn't peform the entire addition, but only word-wise in a way that propagates
362+ // the carry.
347363uint64_t hw_json_simd_bitwise_add (uint64_t a , uint64_t b , uint64_t * c ) {
348364 uint64_t d = a + b + * c ;
349365
@@ -394,13 +410,15 @@ uint64_t hw_json_simd_process_chunk(
394410
395411 for (size_t i = 0 ; i < m256_in_len ; ++ i ) {
396412 hw_json_simd_summarise (in_buffer + (i * 32 ),
397- w32_bits_of_d + i ,
398- w32_bits_of_a + i ,
399- w32_bits_of_z + i ,
400- w32_bits_of_q + i ,
401- w32_bits_of_b + i );
413+ w32_bits_of_d + i , // Mask of delimiter characters ':,'
414+ w32_bits_of_a + i , // Mask of opening characters '{['
415+ w32_bits_of_z + i , // Mask of closing characters ']}'
416+ w32_bits_of_q + i , // Mask of quote characters '"'
417+ w32_bits_of_b + i ); // Mask of backslash characters '\'
402418 }
403419
420+ // Generate an escape mask that can tell us which quote characters are escaped
421+ // and which are not.
404422 for (size_t i = 0 ; i < w8_out_len ; ++ i ) {
405423 char w8 = w8_bits_of_b [i ];
406424 size_t j = (* last_trailing_ones ) % 2 ;
@@ -411,22 +429,45 @@ uint64_t hw_json_simd_process_chunk(
411429 }
412430
413431 for (size_t i = 0 ; i < w64_out_len ; ++ i ) {
432+ // Use the escape mask to remove the escaped quote characters from the quote mask
414433 w64_bits_of_q [i ] = w64_bits_of_e [i ] & w64_bits_of_q [i ];
415434
416435 uint64_t w64_bits_of_q_word = w64_bits_of_q [i ];
417436
418- uint64_t qas = _pdep_u64 (0x5555555555555555 << ((* quote_odds_carry ) & 1 ), w64_bits_of_q_word );
419- uint64_t qzs = _pdep_u64 (0x5555555555555555 << ((* quote_evens_carry ) & 1 ), w64_bits_of_q_word );
420-
437+ // In the following, the bitmask 0x5555555555555555 has all the odd bits selected. For example:
438+ // 0101010101010101010101010101010101010101010101010101010101010101.
439+ // Figure out which quote characters are open (qas) and which are closing quotes (qaz).
440+ // Whether or not the quote is open or closed depends on if there has been unpaired
441+ // quote carrying over from the previous fragment.
442+ uint64_t qas = _pdep_u64 (0x5555555555555555 << ((* quote_odds_carry ) & 1 ), w64_bits_of_q_word ); // All the open quotes
443+ uint64_t qzs = _pdep_u64 (0x5555555555555555 << ((* quote_evens_carry ) & 1 ), w64_bits_of_q_word ); // All the closed quotes
444+
445+ // The quote mask tells us which characters are eligible to be interesting-bits (ie the ones not
446+ // inside a string literal).
447+
448+ // Example:
449+ // input: *"__"*""**"__""_ <- every character that is '*' is unquoted and _ is quoted
450+ // quote_mask_carry: 0
451+ // w64_bits_of_q_word: 0100101100100110
452+ // qas: 0100001000100010
453+ // qaz: 0000100100000100
454+ // ~qaz: 1111011011111011
455+ // quote_mask: 1000110111000100
456+ // input: *"__"*""**"__""_ <- every character that is '*' is unquoted and _ is quoted
457+ // In the above quote_mask and input, every * (unquoted) matches a 1 and every _ (quoted) matches a 0.
458+ // We don't care about the rest of the bits because they correspond to quotes which cannot be
459+ // interesting-bits.
421460 uint64_t quote_mask = hw_json_simd_bitwise_add (qas , ~qzs , quote_mask_carry );
422461
462+ // Only characters outside of string literals a eligible to be interesting-bits so the
463+ // others are masked out.
423464 uint64_t w64_d = quote_mask & w64_bits_of_d [i ];
424465 uint64_t w64_a = quote_mask & w64_bits_of_a [i ];
425466 uint64_t w64_z = quote_mask & w64_bits_of_z [i ];
426467
427- w64_result_ib [i ] = w64_d | w64_a | w64_z ;
428- w64_result_a [i ] = w64_a ;
429- w64_result_z [i ] = w64_z ;
468+ w64_result_ib [i ] = w64_d | w64_a | w64_z ; // Interesting bits
469+ w64_result_a [i ] = w64_a ; // Opening characters
470+ w64_result_z [i ] = w64_z ; // Closing characters
430471
431472 size_t pc = __builtin_popcountll (w64_bits_of_q [i ]);
432473 * quote_odds_carry += pc ;
0 commit comments