diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2025-02-22 11:36:42 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-22 11:36:42 +0100 |
| commit | 1df3a35bca9ff2c23073fabc2d7e6e336d7790f6 (patch) | |
| tree | 4f7afff7051cbc35afd3087b8b53bd19f276fc53 | |
| parent | b6d3be4948e92fce0236cbbe22b55c55f6950269 (diff) | |
| parent | 97bc99a18f8175bf251a902fe5956e4d42fecebb (diff) | |
| download | rust-1df3a35bca9ff2c23073fabc2d7e6e336d7790f6.tar.gz rust-1df3a35bca9ff2c23073fabc2d7e6e336d7790f6.zip | |
Rollup merge of #136910 - okaneco:sig_ones, r=thomcc
Implement feature `isolate_most_least_significant_one` for integer types
Accepted ACP - https://github.com/rust-lang/libs-team/issues/467
Tracking issue - #136909
Implement ACP for functions that isolate the most significant set bit and least significant set bit on unsigned, signed, and `NonZero` integers.
Add function `isolate_most_significant_one`
Add function `isolate_least_significant_one`
---
This PR adds the following impls
```rust
impl {u8, u16, u32, u64, u128, usize} {
const fn isolate_most_significant_one(self) -> Self;
const fn isolate_least_significant_one(self) -> Self;
}
impl {i8, i16, i32, i64, i128, isize} {
const fn isolate_most_significant_one(self) -> Self;
const fn isolate_least_significant_one(self) -> Self;
}
impl NonZeroT {
const fn isolate_most_significant_one(self) -> Self;
const fn isolate_least_significant_one(self) -> Self;
}
```
Example behavior
```rust
assert_eq!(u8::isolate_most_significant_one(0b01100100), 0b01000000);
assert_eq!(u8::isolate_least_significant_one(0b01100100), 0b00000100);
```
| -rw-r--r-- | library/core/src/num/int_macros.rs | 46 | ||||
| -rw-r--r-- | library/core/src/num/nonzero.rs | 64 | ||||
| -rw-r--r-- | library/core/src/num/uint_macros.rs | 46 | ||||
| -rw-r--r-- | library/coretests/tests/lib.rs | 1 | ||||
| -rw-r--r-- | library/coretests/tests/nonzero.rs | 100 | ||||
| -rw-r--r-- | library/coretests/tests/num/int_macros.rs | 34 | ||||
| -rw-r--r-- | library/coretests/tests/num/uint_macros.rs | 34 |
7 files changed, 325 insertions, 0 deletions
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 296b5ebdfaf..74221e21687 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -183,6 +183,52 @@ macro_rules! int_impl { (self as $UnsignedT).trailing_ones() } + /// Returns `self` with only the most significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_most_significant_one(), 0b_01000000); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros())) + } + + /// Returns `self` with only the least significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_least_significant_one(), 0b_00000100); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + self & self.wrapping_neg() + } + /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index b59451d7c75..b94b492e8e1 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -605,6 +605,70 @@ macro_rules! nonzero_integer { } } + /// Returns `self` with only the most significant bit set. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")] + #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_01000000)?;")] + /// + /// assert_eq!(a.isolate_most_significant_one(), b); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + let n = self.get() & (((1 as $Int) << (<$Int>::BITS - 1)).wrapping_shr(self.leading_zeros())); + + // SAFETY: + // `self` is non-zero, so masking to preserve only the most + // significant set bit will result in a non-zero `n`. + unsafe { NonZero::new_unchecked(n) } + } + + /// Returns `self` with only the least significant bit set. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")] + #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_00000100)?;")] + /// + /// assert_eq!(a.isolate_least_significant_one(), b); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + let n = self.get(); + let n = n & n.wrapping_neg(); + + // SAFETY: `self` is non-zero, so `self` with only its least + // significant set bit will remain non-zero. + unsafe { NonZero::new_unchecked(n) } + } + /// Returns the number of ones in the binary representation of `self`. /// /// # Examples diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 74d3ae699f6..289bc48acde 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -213,6 +213,52 @@ macro_rules! uint_impl { (!self).trailing_zeros() } + /// Returns `self` with only the most significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_most_significant_one(), 0b_01000000); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros())) + } + + /// Returns `self` with only the least significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_least_significant_one(), 0b_00000100); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + self & self.wrapping_neg() + } + /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ca58f41d7dd..eb6a8d85a30 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(ip)] #![feature(ip_from)] #![feature(is_ascii_octdigit)] +#![feature(isolate_most_least_significant_one)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_chain)] diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs index 43c279053d8..bdc5701d9fd 100644 --- a/library/coretests/tests/nonzero.rs +++ b/library/coretests/tests/nonzero.rs @@ -322,6 +322,106 @@ fn nonzero_trailing_zeros() { } #[test] +fn test_nonzero_isolate_most_significant_one() { + // Signed most significant one + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = -1; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(), + NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one() + ); + i += 1; + } + } + )+ + }; + } + + // Unsigned most significant one + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = <$T>::MAX; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(), + NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one(), + ); + i += 1; + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} + +#[test] +fn test_nonzero_isolate_least_significant_one() { + // Signed least significant one + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = -1; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(), + NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one() + ); + i += 1; + } + } + )+ + }; + } + + // Unsigned least significant one + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = <$T>::MAX; + const LEAST_SIG_ONE: $T = 1; + + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(), + NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one(), + ); + i += 1; + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} + +#[test] fn test_nonzero_uint_div() { let nz = NonZero::new(1).unwrap(); diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index f13b836378b..392704e7509 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -193,6 +193,40 @@ macro_rules! int_module { } #[test] + fn test_isolate_most_significant_one() { + const BITS: $T = -1; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS >> i).isolate_most_significant_one(), + (MOST_SIG_ONE >> i).isolate_most_significant_one() + ); + i += 1; + } + } + + #[test] + fn test_isolate_least_significant_one() { + const BITS: $T = -1; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS << i).isolate_least_significant_one(), + (LEAST_SIG_ONE << i).isolate_least_significant_one() + ); + i += 1; + } + } + + #[test] fn test_from_str() { fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> { std::str::FromStr::from_str(t).ok() diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 99a2d4cd462..c085ba5a249 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -141,6 +141,40 @@ macro_rules! uint_module { } } + #[test] + fn test_isolate_most_significant_one() { + const BITS: $T = <$T>::MAX; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS >> i).isolate_most_significant_one(), + (MOST_SIG_ONE >> i).isolate_most_significant_one(), + ); + i += 1; + } + } + + #[test] + fn test_isolate_least_significant_one() { + const BITS: $T = <$T>::MAX; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS << i).isolate_least_significant_one(), + (LEAST_SIG_ONE << i).isolate_least_significant_one(), + ); + i += 1; + } + } + fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> { core::str::FromStr::from_str(t).ok() } |
