@@ -1413,6 +1413,66 @@ macro_rules! int_impl {
14131413 }
14141414 }
14151415
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+
14161476 /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
14171477 /// larger than or equal to the number of bits in `self`.
14181478 ///
@@ -1534,6 +1594,63 @@ macro_rules! int_impl {
15341594 }
15351595 }
15361596
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+
15371654 /// Checked absolute value. Computes `self.abs()`, returning `None` if
15381655 /// `self == MIN`.
15391656 ///
0 commit comments