@@ -118,10 +118,10 @@ typedef struct _search_state {
118118#ifdef HAVE_SIMD
119119 const char * chunk_base ;
120120 const char * chunk_end ;
121- bool has_matches ;
121+ // bool has_matches;
122122
123123#if defined(HAVE_SIMD_NEON )
124- uint64_t matches_mask ;
124+ // uint64_t matches_mask;
125125#elif defined(HAVE_SIMD_SSE2 )
126126 int matches_mask ;
127127#else
@@ -174,21 +174,23 @@ static inline unsigned char search_escape_basic(search_state *search)
174174ALWAYS_INLINE (static ) void escape_UTF8_char_basic (search_state * search )
175175{
176176 const unsigned char ch = (unsigned char )* search -> ptr ;
177+ fbuffer_inc_capa (search -> buffer , 6 );
178+ fbuffer_append_reserved_char (search -> buffer , '\\' );
177179 switch (ch ) {
178- case '"' : fbuffer_append (search -> buffer , "\\\"" , 2 ); break ;
179- case '\\' : fbuffer_append (search -> buffer , "\\\\" , 2 ); break ;
180- case '/' : fbuffer_append (search -> buffer , "\\/" , 2 ); break ;
181- case '\b' : fbuffer_append (search -> buffer , "\\b" , 2 ); break ;
182- case '\f' : fbuffer_append (search -> buffer , "\\f" , 2 ); break ;
183- case '\n' : fbuffer_append (search -> buffer , "\\n" , 2 ); break ;
184- case '\r' : fbuffer_append (search -> buffer , "\\r" , 2 ); break ;
185- case '\t' : fbuffer_append (search -> buffer , "\\t" , 2 ); break ;
180+ case '"' : fbuffer_append_reserved_char (search -> buffer , '"' ); break ;
181+ case '\\' : fbuffer_append_reserved_char (search -> buffer , '\\' ); break ;
182+ case '/' : fbuffer_append_reserved_char (search -> buffer , '/' ); break ;
183+ case '\b' : fbuffer_append_reserved_char (search -> buffer , 'b' ); break ;
184+ case '\f' : fbuffer_append_reserved_char (search -> buffer , 'f' ); break ;
185+ case '\n' : fbuffer_append_reserved_char (search -> buffer , 'n' ); break ;
186+ case '\r' : fbuffer_append_reserved_char (search -> buffer , 'r' ); break ;
187+ case '\t' : fbuffer_append_reserved_char (search -> buffer , 't' ); break ;
186188 default : {
187189 const char * hexdig = "0123456789abcdef" ;
188- char scratch [6 ] = { '\\' , 'u' , '0' , '0' , 0 , 0 };
189- scratch [4 ] = hexdig [(ch >> 4 ) & 0xf ];
190- scratch [5 ] = hexdig [ch & 0xf ];
191- fbuffer_append (search -> buffer , scratch , 6 );
190+ char scratch [5 ] = { 'u' , '0' , '0' , 0 , 0 };
191+ scratch [3 ] = hexdig [(ch >> 4 ) & 0xf ];
192+ scratch [4 ] = hexdig [ch & 0xf ];
193+ fbuffer_append (search -> buffer , scratch , 5 );
192194 break ;
193195 }
194196 }
@@ -215,7 +217,8 @@ ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
215217
216218
217219#if defined(HAVE_SIMD_NEON )
218- static inline unsigned char search_escape_basic_neon (search_state * search );
220+ static inline uint64_t search_escape_basic_neon (search_state * search );
221+ static inline uint64_t neon_next_match (uint64_t mask , search_state * search );
219222#elif defined(HAVE_SIMD_SSE2 )
220223static inline unsigned char search_escape_basic_sse2 (search_state * search );
221224#endif
@@ -226,8 +229,19 @@ static inline void convert_UTF8_to_JSON(search_state *search)
226229{
227230#ifdef HAVE_SIMD
228231#if defined(HAVE_SIMD_NEON )
229- while (search_escape_basic_neon (search )) {
230- escape_UTF8_char_basic (search );
232+ uint64_t mask ;
233+ while ((mask = search_escape_basic_neon (search ))) {
234+ while (mask > 0 ) {
235+ mask = neon_next_match (mask , search );
236+ escape_UTF8_char_basic (search );
237+ }
238+ search -> ptr = search -> chunk_end ;
239+ }
240+
241+ if (search -> ptr < search -> end ) {
242+ while (search_escape_basic (search )) {
243+ escape_UTF8_char_basic (search );
244+ }
231245 }
232246#elif defined(HAVE_SIMD_SSE2 )
233247 if (simd_impl == SIMD_SSE2 ) {
@@ -317,9 +331,8 @@ ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned
317331
318332#ifdef HAVE_SIMD_NEON
319333
320- ALWAYS_INLINE (static ) unsigned char neon_next_match (search_state * search )
334+ ALWAYS_INLINE (static ) uint64_t neon_next_match (uint64_t mask , search_state * search )
321335{
322- uint64_t mask = search -> matches_mask ;
323336 uint32_t index = trailing_zeros64 (mask ) >> 2 ;
324337
325338 // It is assumed escape_UTF8_char_basic will only ever increase search->ptr by at most one character.
@@ -329,26 +342,15 @@ ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
329342 // is one byte after the previous match then:
330343 // search->chunk_base + index == search->ptr
331344 search -> ptr = search -> chunk_base + index ;
332- mask &= mask - 1 ;
333- search -> matches_mask = mask ;
334345 search_flush (search );
335- return 1 ;
346+
347+ mask &= mask - 1 ;
348+ // search->matches_mask = mask;
349+ return mask ;
336350}
337351
338- static inline unsigned char search_escape_basic_neon (search_state * search )
352+ static inline uint64_t search_escape_basic_neon (search_state * search )
339353{
340- if (RB_UNLIKELY (search -> has_matches )) {
341- // There are more matches if search->matches_mask > 0.
342- if (search -> matches_mask > 0 ) {
343- return neon_next_match (search );
344- } else {
345- // neon_next_match will only advance search->ptr up to the last matching character.
346- // Skip over any characters in the last chunk that occur after the last match.
347- search -> has_matches = false;
348- search -> ptr = search -> chunk_end ;
349- }
350- }
351-
352354 /*
353355 * The code below implements an SIMD-based algorithm to determine if N bytes at a time
354356 * need to be escaped.
@@ -390,11 +392,12 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
390392 * have at least one byte that needs to be escaped.
391393 */
392394
393- if (string_scan_simd_neon (& search -> ptr , search -> end , & search -> matches_mask )) {
394- search -> has_matches = true;
395+ uint64_t matches_mask = 0 ;
396+ if ((matches_mask = string_scan_simd_neon (& search -> ptr , search -> end ))) {
397+ // search->has_matches = true;
395398 search -> chunk_base = search -> ptr ;
396399 search -> chunk_end = search -> ptr + sizeof (uint8x16_t );
397- return neon_next_match ( search ) ;
400+ return matches_mask ;
398401 }
399402
400403 // There are fewer than 16 bytes left.
@@ -413,15 +416,11 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
413416 return 0 ;
414417 }
415418
416- search -> matches_mask = mask ;
417- search -> has_matches = true;
419+ // search->matches_mask = mask;
420+ // search->has_matches = true;
418421 search -> chunk_end = search -> end ;
419422 search -> chunk_base = search -> ptr ;
420- return neon_next_match (search );
421- }
422-
423- if (search -> ptr < search -> end ) {
424- return search_escape_basic (search );
423+ return mask ;
425424 }
426425
427426 search_flush (search );
@@ -1124,8 +1123,8 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
11241123 search .end = search .ptr + len ;
11251124
11261125#ifdef HAVE_SIMD
1127- search .matches_mask = 0 ;
1128- search .has_matches = false;
1126+ // search.matches_mask = 0;
1127+ // search.has_matches = false;
11291128 search .chunk_base = NULL ;
11301129 search .chunk_end = NULL ;
11311130#endif /* HAVE_SIMD */
0 commit comments