Skip to content

Commit b4b678c

Browse files
committed
add exact bitshifts
1 parent a7a1618 commit b4b678c

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
@@ -1386,6 +1386,57 @@ macro_rules! int_impl {
13861386
}
13871387
}
13881388

1389+
/// Exact shift left. Computes `self << rhs`, returning `None` if any bits disagreeing with
1390+
/// the resulting sign bit would be shifted out.
1391+
///
1392+
/// # Examples
1393+
///
1394+
/// ```
1395+
/// #![feature(exact_bitshifts)]
1396+
///
1397+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
1398+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
1399+
/// ```
1400+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1401+
#[must_use = "this returns the result of the operation, \
1402+
without modifying the original"]
1403+
#[inline]
1404+
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
1405+
if rhs < self.leading_zeros().max(self.leading_ones()) {
1406+
// SAFETY: rhs is checked above
1407+
Some(unsafe { self.unchecked_shl(rhs) })
1408+
} else {
1409+
None
1410+
}
1411+
}
1412+
1413+
/// Unchecked exact shift left. Computes `self << rhs`, assuming bits disagreeing with the
1414+
/// resulting sign bit cannot be shifted out.
1415+
///
1416+
/// # Safety
1417+
///
1418+
/// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
1419+
/// self.leading_ones()` i.e. when
1420+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
1421+
/// would return `None`.
1422+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1423+
#[must_use = "this returns the result of the operation, \
1424+
without modifying the original"]
1425+
#[inline]
1426+
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
1427+
assert_unsafe_precondition!(
1428+
check_language_ub,
1429+
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
1430+
(
1431+
len: u32 = self.leading_zeros().max(self.leading_ones()),
1432+
rhs: u32 = rhs,
1433+
) => rhs < len,
1434+
);
1435+
1436+
// SAFETY: this is guaranteed to be safe by the caller
1437+
unsafe { self.unchecked_shl(rhs) }
1438+
}
1439+
13891440
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
13901441
/// larger than or equal to the number of bits in `self`.
13911442
///
@@ -1508,6 +1559,60 @@ macro_rules! int_impl {
15081559
}
15091560
}
15101561

1562+
/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
1563+
/// shifted out or if `rhs` >=
1564+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1565+
///
1566+
/// # Examples
1567+
///
1568+
/// ```
1569+
/// #![feature(exact_bitshifts)]
1570+
///
1571+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
1572+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
1573+
/// ```
1574+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1575+
#[must_use = "this returns the result of the operation, \
1576+
without modifying the original"]
1577+
#[inline]
1578+
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
1579+
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
1580+
// SAFETY: rhs is checked above
1581+
Some(unsafe { self.unchecked_shr(rhs) })
1582+
} else {
1583+
None
1584+
}
1585+
}
1586+
1587+
/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
1588+
/// shifted out and `rhs` cannot be larger than
1589+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1590+
///
1591+
/// # Safety
1592+
///
1593+
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
1594+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1595+
/// i.e. when
1596+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
1597+
/// would return `None`.
1598+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1599+
#[must_use = "this returns the result of the operation, \
1600+
without modifying the original"]
1601+
#[inline]
1602+
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
1603+
assert_unsafe_precondition!(
1604+
check_language_ub,
1605+
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
1606+
(
1607+
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
1608+
rhs: u32 = rhs,
1609+
) => rhs <= len,
1610+
);
1611+
1612+
// SAFETY: this is guaranteed to be safe by the caller
1613+
unsafe { self.unchecked_shr(rhs) }
1614+
}
1615+
15111616
/// Checked absolute value. Computes `self.abs()`, returning `None` if
15121617
/// `self == MIN`.
15131618
///

library/core/src/num/uint_macros.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,60 @@ macro_rules! uint_impl {
17051705
}
17061706
}
17071707

1708+
/// Exact shift left. Computes `self << rhs`, returning `None` if any non-zero bits would be
1709+
/// shifted out or if `rhs` >=
1710+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1711+
///
1712+
/// # Examples
1713+
///
1714+
/// ```
1715+
/// #![feature(exact_bitshifts)]
1716+
///
1717+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
1718+
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
1719+
/// ```
1720+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1721+
#[must_use = "this returns the result of the operation, \
1722+
without modifying the original"]
1723+
#[inline]
1724+
pub fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
1725+
if rhs <= self.leading_zeros().max(<$SelfT>::BITS - 1) {
1726+
// SAFETY: rhs is checked above
1727+
Some(unsafe { self.unchecked_shl(rhs) })
1728+
} else {
1729+
None
1730+
}
1731+
}
1732+
1733+
/// Unchecked exact shift left. Computes `self << rhs`, assuming non-zero bits cannot be
1734+
/// shifted out and `rhs` cannot be larger than
1735+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1736+
///
1737+
/// # Safety
1738+
///
1739+
/// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
1740+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1741+
/// i.e. when
1742+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
1743+
/// would return `None`.
1744+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1745+
#[must_use = "this returns the result of the operation, \
1746+
without modifying the original"]
1747+
#[inline]
1748+
pub unsafe fn exact_shl_unchecked(self, rhs: u32) -> $SelfT {
1749+
assert_unsafe_precondition!(
1750+
check_language_ub,
1751+
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
1752+
(
1753+
len: u32 = self.leading_zeros().max(<$SelfT>::BITS - 1),
1754+
rhs: u32 = rhs,
1755+
) => rhs <= len,
1756+
);
1757+
1758+
// SAFETY: this is guaranteed to be safe by the caller
1759+
unsafe { self.unchecked_shl(rhs) }
1760+
}
1761+
17081762
/// Checked shift right. Computes `self >> rhs`, returning `None`
17091763
/// if `rhs` is larger than or equal to the number of bits in `self`.
17101764
///
@@ -1821,6 +1875,60 @@ macro_rules! uint_impl {
18211875
}
18221876
}
18231877

1878+
/// Exact shift right. Computes `self >> rhs`, returning `None` if any non-zero bits would be
1879+
/// shifted out or if `rhs` >=
1880+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1881+
///
1882+
/// # Examples
1883+
///
1884+
/// ```
1885+
/// #![feature(exact_bitshifts)]
1886+
///
1887+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
1888+
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(129), None);")]
1889+
/// ```
1890+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1891+
#[must_use = "this returns the result of the operation, \
1892+
without modifying the original"]
1893+
#[inline]
1894+
pub fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
1895+
if rhs <= self.trailing_zeros().max(<$SelfT>::BITS - 1) {
1896+
// SAFETY: rhs is checked above
1897+
Some(unsafe { self.unchecked_shr(rhs) })
1898+
} else {
1899+
None
1900+
}
1901+
}
1902+
1903+
/// Unchecked exact shift right. Computes `self >> rhs`, assuming non-zero bits cannot be
1904+
/// shifted out and `rhs` cannot be larger than
1905+
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
1906+
///
1907+
/// # Safety
1908+
///
1909+
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
1910+
#[doc = concat!(stringify!($SelfT), "::BITS`")]
1911+
/// i.e. when
1912+
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
1913+
/// would return `None`.
1914+
#[unstable(feature = "exact_bitshifts", issue = "144336")]
1915+
#[must_use = "this returns the result of the operation, \
1916+
without modifying the original"]
1917+
#[inline]
1918+
pub unsafe fn exact_shr_unchecked(self, rhs: u32) -> $SelfT {
1919+
assert_unsafe_precondition!(
1920+
check_language_ub,
1921+
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
1922+
(
1923+
len: u32 = self.trailing_zeros().max(<$SelfT>::BITS - 1),
1924+
rhs: u32 = rhs,
1925+
) => rhs <= len,
1926+
);
1927+
1928+
// SAFETY: this is guaranteed to be safe by the caller
1929+
unsafe { self.unchecked_shr(rhs) }
1930+
}
1931+
18241932
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
18251933
/// overflow occurred.
18261934
///

0 commit comments

Comments
 (0)