@@ -31,17 +31,9 @@ fn sub(a: *const u8, b: *const u8) -> usize {
31
31
32
32
#[ target_feature( enable = "avx512f" , enable = "avx512bw" ) ]
33
33
#[ inline]
34
- pub unsafe fn escape_avx512 < S : AsRef < str > > ( input : S ) -> String {
35
- let s = input. as_ref ( ) ;
36
- let bytes = s. as_bytes ( ) ;
34
+ pub unsafe fn escape_avx512 ( bytes : & [ u8 ] , result : & mut Vec < u8 > ) {
37
35
let len = bytes. len ( ) ;
38
36
39
- // Pre-allocate with estimated capacity
40
- let estimated_capacity = len + len / 2 + 2 ;
41
- let mut result = Vec :: with_capacity ( estimated_capacity) ;
42
-
43
- result. push ( b'"' ) ;
44
-
45
37
let start_ptr = bytes. as_ptr ( ) ;
46
38
let end_ptr = bytes[ len..] . as_ptr ( ) ;
47
39
let mut ptr = start_ptr;
@@ -80,7 +72,7 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
80
72
if start < i {
81
73
result. extend_from_slice ( & bytes[ start..i] ) ;
82
74
}
83
- write_escape ( & mut result, escape_byte, c) ;
75
+ write_escape ( result, escape_byte, c) ;
84
76
start = i + 1 ;
85
77
mask &= mask - 1 ;
86
78
}
@@ -143,11 +135,11 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
143
135
start = sub ( ptr, start_ptr) + LOOP_SIZE_AVX512 ;
144
136
} else {
145
137
// Process each 64-byte chunk that has escapes
146
- process_mask_avx512 ( ptr, start_ptr, & mut result, & mut start, bytes, mask_a, 0 ) ;
138
+ process_mask_avx512 ( ptr, start_ptr, result, & mut start, bytes, mask_a, 0 ) ;
147
139
process_mask_avx512 (
148
140
ptr,
149
141
start_ptr,
150
- & mut result,
142
+ result,
151
143
& mut start,
152
144
bytes,
153
145
mask_b,
@@ -156,7 +148,7 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
156
148
process_mask_avx512 (
157
149
ptr,
158
150
start_ptr,
159
- & mut result,
151
+ result,
160
152
& mut start,
161
153
bytes,
162
154
mask_c,
@@ -165,7 +157,7 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
165
157
process_mask_avx512 (
166
158
ptr,
167
159
start_ptr,
168
- & mut result,
160
+ result,
169
161
& mut start,
170
162
bytes,
171
163
mask_d,
@@ -199,7 +191,7 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
199
191
if start < i {
200
192
result. extend_from_slice ( & bytes[ start..i] ) ;
201
193
}
202
- write_escape ( & mut result, escape_byte, c) ;
194
+ write_escape ( result, escape_byte, c) ;
203
195
start = i + 1 ;
204
196
mask &= mask - 1 ;
205
197
}
@@ -229,39 +221,28 @@ pub unsafe fn escape_avx512<S: AsRef<str>>(input: S) -> String {
229
221
if start < i {
230
222
result. extend_from_slice ( & bytes[ start..i] ) ;
231
223
}
232
- write_escape ( & mut result, escape_byte, c) ;
224
+ write_escape ( result, escape_byte, c) ;
233
225
start = i + 1 ;
234
226
mask &= mask - 1 ;
235
227
}
236
228
}
237
229
}
238
230
} else {
239
231
// Fall back to AVX2 for small strings
240
- return escape_avx2 ( input ) ;
232
+ return escape_avx2 ( bytes , result ) ;
241
233
}
242
234
243
235
// Copy any remaining bytes
244
236
if start < len {
245
237
result. extend_from_slice ( & bytes[ start..] ) ;
246
238
}
247
-
248
- result. push ( b'"' ) ;
249
- unsafe { String :: from_utf8_unchecked ( result) }
250
239
}
251
240
252
241
#[ target_feature( enable = "avx2" ) ]
253
242
#[ inline]
254
- pub unsafe fn escape_avx2 < S : AsRef < str > > ( input : S ) -> String {
255
- let s = input. as_ref ( ) ;
256
- let bytes = s. as_bytes ( ) ;
243
+ pub unsafe fn escape_avx2 ( bytes : & [ u8 ] , result : & mut Vec < u8 > ) {
257
244
let len = bytes. len ( ) ;
258
245
259
- // Pre-allocate with estimated capacity
260
- let estimated_capacity = len + len / 2 + 2 ;
261
- let mut result = Vec :: with_capacity ( estimated_capacity) ;
262
-
263
- result. push ( b'"' ) ;
264
-
265
246
let start_ptr = bytes. as_ptr ( ) ;
266
247
let end_ptr = bytes[ len..] . as_ptr ( ) ;
267
248
let mut ptr = start_ptr;
@@ -297,7 +278,7 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
297
278
if start < i {
298
279
result. extend_from_slice ( & bytes[ start..i] ) ;
299
280
}
300
- write_escape ( & mut result, escape_byte, c) ;
281
+ write_escape ( result, escape_byte, c) ;
301
282
start = i + 1 ;
302
283
}
303
284
mask ^= 1 << cur;
@@ -372,11 +353,11 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
372
353
let mask_d = _mm256_movemask_epi8 ( cmp_d) ;
373
354
374
355
// Process each 32-byte chunk that has escapes
375
- process_mask_avx ( ptr, start_ptr, & mut result, & mut start, bytes, mask_a, 0 ) ;
356
+ process_mask_avx ( ptr, start_ptr, result, & mut start, bytes, mask_a, 0 ) ;
376
357
process_mask_avx (
377
358
ptr,
378
359
start_ptr,
379
- & mut result,
360
+ result,
380
361
& mut start,
381
362
bytes,
382
363
mask_b,
@@ -385,7 +366,7 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
385
366
process_mask_avx (
386
367
ptr,
387
368
start_ptr,
388
- & mut result,
369
+ result,
389
370
& mut start,
390
371
bytes,
391
372
mask_c,
@@ -394,7 +375,7 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
394
375
process_mask_avx (
395
376
ptr,
396
377
start_ptr,
397
- & mut result,
378
+ result,
398
379
& mut start,
399
380
bytes,
400
381
mask_d,
@@ -428,7 +409,7 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
428
409
if start < i {
429
410
result. extend_from_slice ( & bytes[ start..i] ) ;
430
411
}
431
- write_escape ( & mut result, escape_byte, c) ;
412
+ write_escape ( result, escape_byte, c) ;
432
413
start = i + 1 ;
433
414
}
434
415
mask ^= 1 << cur;
@@ -464,7 +445,7 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
464
445
if start < i {
465
446
result. extend_from_slice ( & bytes[ start..i] ) ;
466
447
}
467
- write_escape ( & mut result, escape_byte, c) ;
448
+ write_escape ( result, escape_byte, c) ;
468
449
start = i + 1 ;
469
450
}
470
451
mask ^= 1 << cur;
@@ -477,30 +458,20 @@ pub unsafe fn escape_avx2<S: AsRef<str>>(input: S) -> String {
477
458
}
478
459
} else {
479
460
// Fall back to SSE2 for small strings
480
- return escape_sse2 ( input ) ;
461
+ return escape_sse2 ( bytes , result ) ;
481
462
}
482
463
483
464
// Copy any remaining bytes
484
465
if start < len {
485
466
result. extend_from_slice ( & bytes[ start..] ) ;
486
467
}
487
-
488
- result. push ( b'"' ) ;
489
- unsafe { String :: from_utf8_unchecked ( result) }
490
468
}
491
469
492
470
#[ target_feature( enable = "sse2" ) ]
493
471
#[ inline]
494
- pub unsafe fn escape_sse2 < S : AsRef < str > > ( input : S ) -> String {
495
- let s = input. as_ref ( ) ;
496
- let bytes = s. as_bytes ( ) ;
472
+ pub unsafe fn escape_sse2 ( bytes : & [ u8 ] , result : & mut Vec < u8 > ) {
497
473
let len = bytes. len ( ) ;
498
474
499
- let estimated_capacity = len + len / 2 + 2 ;
500
- let mut result = Vec :: with_capacity ( estimated_capacity) ;
501
-
502
- result. push ( b'"' ) ;
503
-
504
475
let start_ptr = bytes. as_ptr ( ) ;
505
476
let end_ptr = bytes[ len..] . as_ptr ( ) ;
506
477
let mut ptr = start_ptr;
@@ -518,7 +489,7 @@ pub unsafe fn escape_sse2<S: AsRef<str>>(input: S) -> String {
518
489
if start < i {
519
490
result. extend_from_slice ( & bytes[ start..i] ) ;
520
491
}
521
- write_escape ( & mut result, escape_byte, c) ;
492
+ write_escape ( result, escape_byte, c) ;
522
493
start = i + 1 ;
523
494
}
524
495
ptr = ptr. offset ( 1 ) ;
@@ -552,7 +523,7 @@ pub unsafe fn escape_sse2<S: AsRef<str>>(input: S) -> String {
552
523
if start < i {
553
524
result. extend_from_slice ( & bytes[ start..i] ) ;
554
525
}
555
- write_escape ( & mut result, escape_byte, c) ;
526
+ write_escape ( result, escape_byte, c) ;
556
527
start = i + 1 ;
557
528
}
558
529
mask ^= 1 << cur;
@@ -587,7 +558,7 @@ pub unsafe fn escape_sse2<S: AsRef<str>>(input: S) -> String {
587
558
if start < i {
588
559
result. extend_from_slice ( & bytes[ start..i] ) ;
589
560
}
590
- write_escape ( & mut result, escape_byte, c) ;
561
+ write_escape ( result, escape_byte, c) ;
591
562
start = i + 1 ;
592
563
}
593
564
mask ^= 1 << cur;
@@ -623,7 +594,7 @@ pub unsafe fn escape_sse2<S: AsRef<str>>(input: S) -> String {
623
594
if start < i {
624
595
result. extend_from_slice ( & bytes[ start..i] ) ;
625
596
}
626
- write_escape ( & mut result, escape_byte, c) ;
597
+ write_escape ( result, escape_byte, c) ;
627
598
start = i + 1 ;
628
599
}
629
600
mask ^= 1 << cur;
@@ -640,9 +611,6 @@ pub unsafe fn escape_sse2<S: AsRef<str>>(input: S) -> String {
640
611
if start < len {
641
612
result. extend_from_slice ( & bytes[ start..] ) ;
642
613
}
643
-
644
- result. push ( b'"' ) ;
645
- unsafe { String :: from_utf8_unchecked ( result) }
646
614
}
647
615
648
616
#[ inline( always) ]
0 commit comments