Skip to content

Commit 7a20179

Browse files
committed
add exact bitshifts
1 parent e8a792d commit 7a20179

File tree

2 files changed

+213
-0
lines changed

2 files changed

+213
-0
lines changed

library/core/src/num/int_macros.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,57 @@ macro_rules! int_impl {
14131413
}
14141414
}
14151415

1416+
/// Exact shift left. Computes `self << rhs`, returning `None` if any bits disagreeing with
1417+
/// the resulting sign bit would be shifted out.
1418+
///
1419+
/// # Examples
1420+
///
1421+
/// ```
1422+
/// #![feature(exact_bitshifts)]
1423+
///
1424+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
1425+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
1426+
/// ```
1427+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1428+
#[must_use = "this returns the result of the operation, \
1429+
without modifying the original"]
1430+
#[inline]
1431+
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
1432+
if rhs < self.leading_zeros().max(self.leading_ones()) {
1433+
// SAFETY: rhs is checked above
1434+
Some(unsafe { self.unchecked_shl(rhs) })
1435+
} else {
1436+
None
1437+
}
1438+
}
1439+
1440+
/// Unchecked exact shift left. Computes `self << rhs`, assuming bits disagreeing with the
1441+
/// resulting sign bit cannot be shifted out.
1442+
///
1443+
/// # Safety
1444+
///
1445+
/// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
1446+
/// self.leading_ones()` i.e. when
1447+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
1448+
/// would return `None`.
1449+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1450+
#[must_use = "this returns the result of the operation, \
1451+
without modifying the original"]
1452+
#[inline]
1453+
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
1454+
assert_unsafe_precondition!(
1455+
check_language_ub,
1456+
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
1457+
(
1458+
len: u32 = self.leading_zeros().max(self.leading_ones()),
1459+
rhs: u32 = rhs,
1460+
) => rhs < len,
1461+
);
1462+
1463+
// SAFETY: this is guaranteed to be safe by the caller
1464+
unsafe { self.unchecked_shl(rhs) }
1465+
}
1466+
14161467
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
14171468
/// larger than or equal to the number of bits in `self`.
14181469
///
@@ -1534,6 +1585,60 @@ macro_rules! int_impl {
15341585
}
15351586
}
15361587

1588+
/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
1589+
/// shifted out or if `rhs` >=
1590+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1591+
///
1592+
/// # Examples
1593+
///
1594+
/// ```
1595+
/// #![feature(exact_bitshifts)]
1596+
///
1597+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
1598+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
1599+
/// ```
1600+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1601+
#[must_use = "this returns the result of the operation, \
1602+
without modifying the original"]
1603+
#[inline]
1604+
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
1605+
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
1606+
// SAFETY: rhs is checked above
1607+
Some(unsafe { self.unchecked_shr(rhs) })
1608+
} else {
1609+
None
1610+
}
1611+
}
1612+
1613+
/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
1614+
/// shifted out and `rhs` cannot be larger than
1615+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1616+
///
1617+
/// # Safety
1618+
///
1619+
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
1620+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1621+
/// i.e. when
1622+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
1623+
/// would return `None`.
1624+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1625+
#[must_use = "this returns the result of the operation, \
1626+
without modifying the original"]
1627+
#[inline]
1628+
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
1629+
assert_unsafe_precondition!(
1630+
check_language_ub,
1631+
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
1632+
(
1633+
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
1634+
rhs: u32 = rhs,
1635+
) => rhs <= len,
1636+
);
1637+
1638+
// SAFETY: this is guaranteed to be safe by the caller
1639+
unsafe { self.unchecked_shr(rhs) }
1640+
}
1641+
15371642
/// Checked absolute value. Computes `self.abs()`, returning `None` if
15381643
/// `self == MIN`.
15391644
///

library/core/src/num/uint_macros.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,60 @@ macro_rules! uint_impl {
17341734
}
17351735
}
17361736

1737+
/// Exact shift left. Computes `self << rhs`, returning `None` if any non-zero bits would be
1738+
/// shifted out or if `rhs` >=
1739+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1740+
///
1741+
/// # Examples
1742+
///
1743+
/// ```
1744+
/// #![feature(exact_bitshifts)]
1745+
///
1746+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
1747+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
1748+
/// ```
1749+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1750+
#[must_use = "this returns the result of the operation, \
1751+
without modifying the original"]
1752+
#[inline]
1753+
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
1754+
if rhs <= self.leading_zeros().max(<$SelfT>::BITS - 1) {
1755+
// SAFETY: rhs is checked above
1756+
Some(unsafe { self.unchecked_shl(rhs) })
1757+
} else {
1758+
None
1759+
}
1760+
}
1761+
1762+
/// Unchecked exact shift left. Computes `self << rhs`, assuming non-zero bits cannot be
1763+
/// shifted out and `rhs` cannot be larger than
1764+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1765+
///
1766+
/// # Safety
1767+
///
1768+
/// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
1769+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1770+
/// i.e. when
1771+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
1772+
/// would return `None`.
1773+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1774+
#[must_use = "this returns the result of the operation, \
1775+
without modifying the original"]
1776+
#[inline]
1777+
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
1778+
assert_unsafe_precondition!(
1779+
check_language_ub,
1780+
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
1781+
(
1782+
len: u32 = self.leading_zeros().max(<$SelfT>::BITS - 1),
1783+
rhs: u32 = rhs,
1784+
) => rhs <= len,
1785+
);
1786+
1787+
// SAFETY: this is guaranteed to be safe by the caller
1788+
unsafe { self.unchecked_shl(rhs) }
1789+
}
1790+
17371791
/// Checked shift right. Computes `self >> rhs`, returning `None`
17381792
/// if `rhs` is larger than or equal to the number of bits in `self`.
17391793
///
@@ -1849,6 +1903,60 @@ macro_rules! uint_impl {
18491903
}
18501904
}
18511905

1906+
/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
1907+
/// shifted out or if `rhs` >=
1908+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1909+
///
1910+
/// # Examples
1911+
///
1912+
/// ```
1913+
/// #![feature(exact_bitshifts)]
1914+
///
1915+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
1916+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
1917+
/// ```
1918+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1919+
#[must_use = "this returns the result of the operation, \
1920+
without modifying the original"]
1921+
#[inline]
1922+
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
1923+
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
1924+
// SAFETY: rhs is checked above
1925+
Some(unsafe { self.unchecked_shr(rhs) })
1926+
} else {
1927+
None
1928+
}
1929+
}
1930+
1931+
/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
1932+
/// shifted out and `rhs` cannot be larger than
1933+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1934+
///
1935+
/// # Safety
1936+
///
1937+
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
1938+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1939+
/// i.e. when
1940+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
1941+
/// would return `None`.
1942+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1943+
#[must_use = "this returns the result of the operation, \
1944+
without modifying the original"]
1945+
#[inline]
1946+
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
1947+
assert_unsafe_precondition!(
1948+
check_language_ub,
1949+
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
1950+
(
1951+
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
1952+
rhs: u32 = rhs,
1953+
) => rhs <= len,
1954+
);
1955+
1956+
// SAFETY: this is guaranteed to be safe by the caller
1957+
unsafe { self.unchecked_shr(rhs) }
1958+
}
1959+
18521960
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
18531961
/// overflow occurred.
18541962
///

0 commit comments

Comments
 (0)