Skip to content

Commit 87c62a4

Browse files
authored
Rollup merge of rust-lang#144342 - Qelxiros:exact-bitshifts, r=tgross35
add exact bitshifts Tracking issue: rust-lang#144336 cc ```@lolbinarycat```
2 parents 0d0263e + 148de67 commit 87c62a4

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed

core/src/num/int_macros.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
///

core/src/num/uint_macros.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,6 +1821,63 @@ macro_rules! uint_impl {
18211821
}
18221822
}
18231823

1824+
/// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
1825+
///
1826+
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
1827+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1828+
/// Otherwise, returns `Some(self << rhs)`.
1829+
///
1830+
/// # Examples
1831+
///
1832+
/// ```
1833+
/// #![feature(exact_bitshifts)]
1834+
///
1835+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
1836+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
1837+
/// ```
1838+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1839+
#[must_use = "this returns the result of the operation, \
1840+
without modifying the original"]
1841+
#[inline]
1842+
pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
1843+
if rhs <= self.leading_zeros() && rhs < <$SelfT>::BITS {
1844+
// SAFETY: rhs is checked above
1845+
Some(unsafe { self.unchecked_shl(rhs) })
1846+
} else {
1847+
None
1848+
}
1849+
}
1850+
1851+
/// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
1852+
/// losslessly reversed `rhs` cannot be larger than
1853+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1854+
///
1855+
/// # Safety
1856+
///
1857+
/// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
1858+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1859+
/// i.e. when
1860+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
1861+
/// would return `None`.
1862+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1863+
#[must_use = "this returns the result of the operation, \
1864+
without modifying the original"]
1865+
#[inline]
1866+
pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
1867+
assert_unsafe_precondition!(
1868+
check_language_ub,
1869+
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
1870+
(
1871+
zeros: u32 = self.leading_zeros(),
1872+
bits: u32 = <$SelfT>::BITS,
1873+
rhs: u32 = rhs,
1874+
) => rhs <= zeros && rhs < bits,
1875+
);
1876+
1877+
// SAFETY: this is guaranteed to be safe by the caller
1878+
unsafe { self.unchecked_shl(rhs) }
1879+
}
1880+
18241881
/// Checked shift right. Computes `self >> rhs`, returning `None`
18251882
/// if `rhs` is larger than or equal to the number of bits in `self`.
18261883
///
@@ -1936,6 +1993,63 @@ macro_rules! uint_impl {
19361993
}
19371994
}
19381995

1996+
/// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
1997+
///
1998+
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
1999+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
2000+
/// Otherwise, returns `Some(self >> rhs)`.
2001+
///
2002+
/// # Examples
2003+
///
2004+
/// ```
2005+
/// #![feature(exact_bitshifts)]
2006+
///
2007+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
2008+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
2009+
/// ```
2010+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
2011+
#[must_use = "this returns the result of the operation, \
2012+
without modifying the original"]
2013+
#[inline]
2014+
pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
2015+
if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
2016+
// SAFETY: rhs is checked above
2017+
Some(unsafe { self.unchecked_shr(rhs) })
2018+
} else {
2019+
None
2020+
}
2021+
}
2022+
2023+
/// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
2024+
/// losslessly reversed and `rhs` cannot be larger than
2025+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
2026+
///
2027+
/// # Safety
2028+
///
2029+
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
2030+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
2031+
/// i.e. when
2032+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
2033+
/// would return `None`.
2034+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
2035+
#[must_use = "this returns the result of the operation, \
2036+
without modifying the original"]
2037+
#[inline]
2038+
pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
2039+
assert_unsafe_precondition!(
2040+
check_language_ub,
2041+
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
2042+
(
2043+
zeros: u32 = self.trailing_zeros(),
2044+
bits: u32 = <$SelfT>::BITS,
2045+
rhs: u32 = rhs,
2046+
) => rhs <= zeros && rhs < bits,
2047+
);
2048+
2049+
// SAFETY: this is guaranteed to be safe by the caller
2050+
unsafe { self.unchecked_shr(rhs) }
2051+
}
2052+
19392053
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
19402054
/// overflow occurred.
19412055
///

0 commit comments

Comments
 (0)