@@ -176,12 +176,9 @@ impl<'a> Writer<'a> {
176
176
end : usize ,
177
177
) {
178
178
if ( end - start) . next_multiple_of ( core:: mem:: size_of :: < C > ( ) ) <= ( buf. len ( ) - current) {
179
+ let ptr = buf. as_mut_ptr ( ) ;
179
180
unsafe {
180
- Self :: copy_chunk_unchecked :: < C > (
181
- buf. as_ptr ( ) . add ( start) ,
182
- buf. as_mut_ptr ( ) . add ( current) ,
183
- buf. as_ptr ( ) . add ( end) ,
184
- )
181
+ Self :: copy_chunk_unchecked :: < C > ( ptr. add ( start) , ptr. add ( current) , ptr. add ( end) )
185
182
}
186
183
} else {
187
184
// a full simd copy does not fit in the output buffer
@@ -300,3 +297,100 @@ impl Chunk for core::arch::x86_64::__m512i {
300
297
core:: ptr:: write_unaligned ( out. cast ( ) , chunk)
301
298
}
302
299
}
300
+
301
+ #[ cfg( test) ]
302
+ mod test {
303
+ use super :: * ;
304
+
305
+ const N : usize = 128 ;
306
+ const M : usize = 64 ;
307
+
308
+ fn test_array ( ) -> [ MaybeUninit < u8 > ; N ] {
309
+ core:: array:: from_fn ( |i| MaybeUninit :: new ( if i < M { i as u8 } else { 0xAAu8 } ) )
310
+ }
311
+
312
+ fn test_copy_match ( offset_from_end : usize , length : usize ) {
313
+ let mut buf = test_array ( ) ;
314
+ let mut writer = Writer {
315
+ buf : & mut buf,
316
+ filled : M ,
317
+ } ;
318
+ writer. copy_match ( offset_from_end, length) ;
319
+ assert_eq ! ( writer. filled, M + length) ;
320
+
321
+ let mut naive = test_array ( ) ;
322
+ for i in 0 ..length {
323
+ naive[ M + i] = naive[ M - offset_from_end + i] ;
324
+ }
325
+
326
+ let buf = unsafe { core:: mem:: transmute :: < [ MaybeUninit < u8 > ; 128 ] , [ u8 ; N ] > ( buf) } ;
327
+ let naive = unsafe { core:: mem:: transmute :: < [ MaybeUninit < u8 > ; 128 ] , [ u8 ; N ] > ( naive) } ;
328
+ assert_eq ! (
329
+ buf[ M ..] [ ..length] ,
330
+ naive[ M ..] [ ..length] ,
331
+ "{} {}" ,
332
+ offset_from_end,
333
+ length
334
+ ) ;
335
+ }
336
+
337
+ #[ test]
338
+ fn copy_chunk_unchecked ( ) {
339
+ let offset_from_end = 17 ;
340
+ let length = 17 ;
341
+
342
+ #[ cfg( target_arch = "x86_64" ) ]
343
+ use core:: arch:: x86_64:: { __m128i, __m256i, __m512i} ;
344
+
345
+ macro_rules! helper {
346
+ ( $func: expr) => {
347
+ let mut buf = test_array( ) ;
348
+ let mut writer = Writer {
349
+ buf: & mut buf,
350
+ filled: M ,
351
+ } ;
352
+
353
+ $func( & mut writer, offset_from_end, length) ;
354
+ } ;
355
+ }
356
+
357
+ #[ cfg( target_arch = "x86_64" ) ]
358
+ if crate :: cpu_features:: is_enabled_avx512 ( ) {
359
+ helper ! ( Writer :: copy_match_help:: <__m512i>) ;
360
+ }
361
+
362
+ #[ cfg( target_arch = "x86_64" ) ]
363
+ if crate :: cpu_features:: is_enabled_avx2 ( ) {
364
+ helper ! ( Writer :: copy_match_help:: <__m256i>) ;
365
+ }
366
+
367
+ #[ cfg( target_arch = "x86_64" ) ]
368
+ if crate :: cpu_features:: is_enabled_sse ( ) {
369
+ helper ! ( Writer :: copy_match_help:: <__m128i>) ;
370
+ }
371
+
372
+ helper ! ( Writer :: copy_match_help:: <u64 >) ;
373
+ }
374
+
375
+ #[ test]
376
+ fn copy_match ( ) {
377
+ for offset_from_end in 1 ..=64 {
378
+ for length in 0 ..=64 {
379
+ test_copy_match ( offset_from_end, length)
380
+ }
381
+ }
382
+ }
383
+
384
+ #[ test]
385
+ fn copy_match_insufficient_space_for_simd ( ) {
386
+ let mut buf = [ 1 , 2 , 3 , 0xAA , 0xAA ] . map ( MaybeUninit :: new) ;
387
+ let mut writer = Writer {
388
+ buf : & mut buf,
389
+ filled : 3 ,
390
+ } ;
391
+
392
+ writer. copy_match ( 3 , 2 ) ;
393
+
394
+ assert_eq ! ( buf. map( |e| unsafe { e. assume_init( ) } ) , [ 1 , 2 , 3 , 1 , 2 ] ) ;
395
+ }
396
+ }
0 commit comments