@@ -1413,6 +1413,66 @@ macro_rules! int_impl {
1413
1413
}
1414
1414
}
1415
1415
1416
+ /// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
1417
+ ///
1418
+ /// Returns `None` if any bits that would be shifted out differ from the resulting sign bit
1419
+ /// or if `rhs` >=
1420
+ #[ doc = concat!( "`" , stringify!( $SelfT) , "::BITS`." ) ]
1421
+ /// Otherwise, returns `Some(self << rhs)`.
1422
+ ///
1423
+ /// # Examples
1424
+ ///
1425
+ /// ```
1426
+ /// #![feature(exact_bitshifts)]
1427
+ ///
1428
+ #[ doc = concat!( "assert_eq!(0x1" , stringify!( $SelfT) , ".exact_shl(4), Some(0x10));" ) ]
1429
+ #[ doc = concat!( "assert_eq!(0x1" , stringify!( $SelfT) , ".exact_shl(" , stringify!( $SelfT) , "::BITS - 2), Some(1 << " , stringify!( $SelfT) , "::BITS - 2));" ) ]
1430
+ #[ doc = concat!( "assert_eq!(0x1" , stringify!( $SelfT) , ".exact_shl(" , stringify!( $SelfT) , "::BITS - 1), None);" ) ]
1431
+ #[ doc = concat!( "assert_eq!((-0x2" , stringify!( $SelfT) , ").exact_shl(" , stringify!( $SelfT) , "::BITS - 2), Some(-0x2 << " , stringify!( $SelfT) , "::BITS - 2));" ) ]
1432
+ #[ doc = concat!( "assert_eq!((-0x2" , stringify!( $SelfT) , ").exact_shl(" , stringify!( $SelfT) , "::BITS - 1), None);" ) ]
1433
+ /// ```
1434
+ #[ unstable( feature = "exact_bitshifts" , issue = "144336" ) ]
1435
+ #[ must_use = "this returns the result of the operation, \
1436
+ without modifying the original"]
1437
+ #[ inline]
1438
+ pub const fn exact_shl( self , rhs: u32 ) -> Option <$SelfT> {
1439
+ if rhs < self . leading_zeros( ) || rhs < self . leading_ones( ) {
1440
+ // SAFETY: rhs is checked above
1441
+ Some ( unsafe { self . unchecked_shl( rhs) } )
1442
+ } else {
1443
+ None
1444
+ }
1445
+ }
1446
+
1447
+ /// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
1448
+ /// losslessly reversed and `rhs` cannot be larger than
1449
+ #[ doc = concat!( "`" , stringify!( $SelfT) , "::BITS`." ) ]
1450
+ ///
1451
+ /// # Safety
1452
+ ///
1453
+ /// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
1454
+ /// self.leading_ones()` i.e. when
1455
+ #[ doc = concat!( "[`" , stringify!( $SelfT) , "::exact_shl`]" ) ]
1456
+ /// would return `None`.
1457
+ #[ unstable( feature = "exact_bitshifts" , issue = "144336" ) ]
1458
+ #[ must_use = "this returns the result of the operation, \
1459
+ without modifying the original"]
1460
+ #[ inline]
1461
+ pub const unsafe fn unchecked_exact_shl( self , rhs: u32 ) -> $SelfT {
1462
+ assert_unsafe_precondition!(
1463
+ check_language_ub,
1464
+ concat!( stringify!( $SelfT) , "::unchecked_exact_shl cannot shift out non-zero bits" ) ,
1465
+ (
1466
+ zeros: u32 = self . leading_zeros( ) ,
1467
+ ones: u32 = self . leading_ones( ) ,
1468
+ rhs: u32 = rhs,
1469
+ ) => rhs < zeros || rhs < ones,
1470
+ ) ;
1471
+
1472
+ // SAFETY: this is guaranteed to be safe by the caller
1473
+ unsafe { self . unchecked_shl( rhs) }
1474
+ }
1475
+
1416
1476
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
1417
1477
/// larger than or equal to the number of bits in `self`.
1418
1478
///
@@ -1534,6 +1594,63 @@ macro_rules! int_impl {
1534
1594
}
1535
1595
}
1536
1596
1597
+ /// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
1598
+ ///
1599
+ /// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
1600
+ #[ doc = concat!( "`" , stringify!( $SelfT) , "::BITS`." ) ]
1601
+ /// Otherwise, returns `Some(self >> rhs)`.
1602
+ ///
1603
+ /// # Examples
1604
+ ///
1605
+ /// ```
1606
+ /// #![feature(exact_bitshifts)]
1607
+ ///
1608
+ #[ doc = concat!( "assert_eq!(0x10" , stringify!( $SelfT) , ".exact_shr(4), Some(0x1));" ) ]
1609
+ #[ doc = concat!( "assert_eq!(0x10" , stringify!( $SelfT) , ".exact_shr(5), None);" ) ]
1610
+ /// ```
1611
+ #[ unstable( feature = "exact_bitshifts" , issue = "144336" ) ]
1612
+ #[ must_use = "this returns the result of the operation, \
1613
+ without modifying the original"]
1614
+ #[ inline]
1615
+ pub const fn exact_shr( self , rhs: u32 ) -> Option <$SelfT> {
1616
+ if rhs <= self . trailing_zeros( ) && rhs < <$SelfT>:: BITS {
1617
+ // SAFETY: rhs is checked above
1618
+ Some ( unsafe { self . unchecked_shr( rhs) } )
1619
+ } else {
1620
+ None
1621
+ }
1622
+ }
1623
+
1624
+ /// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
1625
+ /// losslessly reversed and `rhs` cannot be larger than
1626
+ #[ doc = concat!( "`" , stringify!( $SelfT) , "::BITS`." ) ]
1627
+ ///
1628
+ /// # Safety
1629
+ ///
1630
+ /// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
1631
+ #[ doc = concat!( stringify!( $SelfT) , "::BITS`" ) ]
1632
+ /// i.e. when
1633
+ #[ doc = concat!( "[`" , stringify!( $SelfT) , "::exact_shr`]" ) ]
1634
+ /// would return `None`.
1635
+ #[ unstable( feature = "exact_bitshifts" , issue = "144336" ) ]
1636
+ #[ must_use = "this returns the result of the operation, \
1637
+ without modifying the original"]
1638
+ #[ inline]
1639
+ pub const unsafe fn unchecked_exact_shr( self , rhs: u32 ) -> $SelfT {
1640
+ assert_unsafe_precondition!(
1641
+ check_language_ub,
1642
+ concat!( stringify!( $SelfT) , "::unchecked_exact_shr cannot shift out non-zero bits" ) ,
1643
+ (
1644
+ zeros: u32 = self . trailing_zeros( ) ,
1645
+ bits: u32 = <$SelfT>:: BITS ,
1646
+ rhs: u32 = rhs,
1647
+ ) => rhs <= zeros && rhs < bits,
1648
+ ) ;
1649
+
1650
+ // SAFETY: this is guaranteed to be safe by the caller
1651
+ unsafe { self . unchecked_shr( rhs) }
1652
+ }
1653
+
1537
1654
/// Checked absolute value. Computes `self.abs()`, returning `None` if
1538
1655
/// `self == MIN`.
1539
1656
///
0 commit comments