@@ -2337,14 +2337,30 @@ impl<'a, T> IntoIterator for &'a mut [T] {
2337
2337
}
2338
2338
}
2339
2339
2340
+ // Inlining is_empty and len makes a huge performance difference
2341
+ macro_rules! is_empty {
2342
+ // The way we encode the length of a ZST iterator, this works both for ZST
2343
+ // and non-ZST.
2344
+ ( $self: expr) => { $self. ptr == $self. end}
2345
+ }
2346
+ macro_rules! len {
2347
+ ( $T: ty, $self: expr) => { {
2348
+ if mem:: size_of:: <$T>( ) == 0 {
2349
+ ( $self. end as usize ) . wrapping_sub( $self. ptr as usize )
2350
+ } else {
2351
+ $self. end. offset_from( $self. ptr) as usize
2352
+ }
2353
+ } }
2354
+ }
2355
+
2340
2356
// The shared definition of the `Iter` and `IterMut` iterators
2341
2357
macro_rules! iterator {
2342
2358
( struct $name: ident -> $ptr: ty, $elem: ty, $raw_mut: tt, $( $mut_: tt ) * ) => {
2343
2359
impl <' a, T > $name<' a, T > {
2344
2360
// Helper function for creating a slice from the iterator.
2345
2361
#[ inline( always) ]
2346
2362
fn make_slice( & self ) -> & ' a [ T ] {
2347
- unsafe { from_raw_parts( self . ptr, self . len( ) ) }
2363
+ unsafe { from_raw_parts( self . ptr, len! ( T , self ) ) }
2348
2364
}
2349
2365
2350
2366
// Helper function for moving the start of the iterator forwards by `offset` elements,
@@ -2382,20 +2398,12 @@ macro_rules! iterator {
2382
2398
impl <' a, T > ExactSizeIterator for $name<' a, T > {
2383
2399
#[ inline( always) ]
2384
2400
fn len( & self ) -> usize {
2385
- let diff = ( self . end as usize ) . wrapping_sub( self . ptr as usize ) ;
2386
- if mem:: size_of:: <T >( ) == 0 {
2387
- // end is really ptr+len, so we are already done
2388
- diff
2389
- } else {
2390
- diff / mem:: size_of:: <T >( )
2391
- }
2401
+ unsafe { len!( T , self ) }
2392
2402
}
2393
2403
2394
2404
#[ inline( always) ]
2395
2405
fn is_empty( & self ) -> bool {
2396
- // The way we encode the length of a ZST iterator, this works both for ZST
2397
- // and non-ZST.
2398
- self . ptr == self . end
2406
+ is_empty!( self )
2399
2407
}
2400
2408
}
2401
2409
@@ -2411,7 +2419,7 @@ macro_rules! iterator {
2411
2419
if mem:: size_of:: <T >( ) != 0 {
2412
2420
assume( !self . end. is_null( ) ) ;
2413
2421
}
2414
- if self . is_empty( ) {
2422
+ if is_empty! ( self ) {
2415
2423
None
2416
2424
} else {
2417
2425
Some ( & $( $mut_ ) * * self . post_inc_start( 1 ) )
@@ -2421,7 +2429,7 @@ macro_rules! iterator {
2421
2429
2422
2430
#[ inline]
2423
2431
fn size_hint( & self ) -> ( usize , Option <usize >) {
2424
- let exact = self . len( ) ;
2432
+ let exact = unsafe { len! ( T , self ) } ;
2425
2433
( exact, Some ( exact) )
2426
2434
}
2427
2435
@@ -2432,7 +2440,7 @@ macro_rules! iterator {
2432
2440
2433
2441
#[ inline]
2434
2442
fn nth( & mut self , n: usize ) -> Option <$elem> {
2435
- if n >= self . len( ) {
2443
+ if n >= unsafe { len! ( T , self ) } {
2436
2444
// This iterator is now empty.
2437
2445
if mem:: size_of:: <T >( ) == 0 {
2438
2446
// We have to do it this way as `ptr` may never be 0, but `end`
@@ -2463,13 +2471,13 @@ macro_rules! iterator {
2463
2471
// manual unrolling is needed when there are conditional exits from the loop
2464
2472
let mut accum = init;
2465
2473
unsafe {
2466
- while self . len( ) >= 4 {
2474
+ while len! ( T , self ) >= 4 {
2467
2475
accum = f( accum, & $( $mut_ ) * * self . post_inc_start( 1 ) ) ?;
2468
2476
accum = f( accum, & $( $mut_ ) * * self . post_inc_start( 1 ) ) ?;
2469
2477
accum = f( accum, & $( $mut_ ) * * self . post_inc_start( 1 ) ) ?;
2470
2478
accum = f( accum, & $( $mut_ ) * * self . post_inc_start( 1 ) ) ?;
2471
2479
}
2472
- while !self . is_empty( ) {
2480
+ while !is_empty! ( self ) {
2473
2481
accum = f( accum, & $( $mut_ ) * * self . post_inc_start( 1 ) ) ?;
2474
2482
}
2475
2483
}
@@ -2539,7 +2547,7 @@ macro_rules! iterator {
2539
2547
if mem:: size_of:: <T >( ) != 0 {
2540
2548
assume( !self . end. is_null( ) ) ;
2541
2549
}
2542
- if self . is_empty( ) {
2550
+ if is_empty! ( self ) {
2543
2551
None
2544
2552
} else {
2545
2553
Some ( & $( $mut_ ) * * self . pre_dec_end( 1 ) )
@@ -2554,13 +2562,14 @@ macro_rules! iterator {
2554
2562
// manual unrolling is needed when there are conditional exits from the loop
2555
2563
let mut accum = init;
2556
2564
unsafe {
2557
- while self . len( ) >= 4 {
2565
+ while len! ( T , self ) >= 4 {
2558
2566
accum = f( accum, & $( $mut_ ) * * self . pre_dec_end( 1 ) ) ?;
2559
2567
accum = f( accum, & $( $mut_ ) * * self . pre_dec_end( 1 ) ) ?;
2560
2568
accum = f( accum, & $( $mut_ ) * * self . pre_dec_end( 1 ) ) ?;
2561
2569
accum = f( accum, & $( $mut_ ) * * self . pre_dec_end( 1 ) ) ?;
2562
2570
}
2563
- while !self . is_empty( ) {
2571
+ // inlining is_empty everywhere makes a huge performance difference
2572
+ while !is_empty!( self ) {
2564
2573
accum = f( accum, & $( $mut_ ) * * self . pre_dec_end( 1 ) ) ?;
2565
2574
}
2566
2575
}
@@ -2760,7 +2769,7 @@ impl<'a, T> IterMut<'a, T> {
2760
2769
/// ```
2761
2770
#[ stable( feature = "iter_to_slice" , since = "1.4.0" ) ]
2762
2771
pub fn into_slice ( self ) -> & ' a mut [ T ] {
2763
- unsafe { from_raw_parts_mut ( self . ptr , self . len ( ) ) }
2772
+ unsafe { from_raw_parts_mut ( self . ptr , len ! ( T , self ) ) }
2764
2773
}
2765
2774
}
2766
2775
0 commit comments