Skip to content

Commit c06a4e9

Browse files
okanecogitbot
authored and
gitbot
committed
Implement feature isolate_most_least_significant_one for integer types
Implement accepted 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` Add tests
1 parent 8664965 commit c06a4e9

File tree

7 files changed

+325
-0
lines changed

7 files changed

+325
-0
lines changed

core/src/num/int_macros.rs

+46
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,52 @@ macro_rules! int_impl {
183183
(self as $UnsignedT).trailing_ones()
184184
}
185185

186+
/// Returns `self` with only the most significant bit set, or `0` if
187+
/// the input is `0`.
188+
///
189+
/// # Examples
190+
///
191+
/// Basic usage:
192+
///
193+
/// ```
194+
/// #![feature(isolate_most_least_significant_one)]
195+
///
196+
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
197+
///
198+
/// assert_eq!(n.isolate_most_significant_one(), 0b_01000000);
199+
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")]
200+
/// ```
201+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
202+
#[must_use = "this returns the result of the operation, \
203+
without modifying the original"]
204+
#[inline(always)]
205+
pub const fn isolate_most_significant_one(self) -> Self {
206+
self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros()))
207+
}
208+
209+
/// Returns `self` with only the least significant bit set, or `0` if
210+
/// the input is `0`.
211+
///
212+
/// # Examples
213+
///
214+
/// Basic usage:
215+
///
216+
/// ```
217+
/// #![feature(isolate_most_least_significant_one)]
218+
///
219+
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
220+
///
221+
/// assert_eq!(n.isolate_least_significant_one(), 0b_00000100);
222+
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")]
223+
/// ```
224+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
225+
#[must_use = "this returns the result of the operation, \
226+
without modifying the original"]
227+
#[inline(always)]
228+
pub const fn isolate_least_significant_one(self) -> Self {
229+
self & self.wrapping_neg()
230+
}
231+
186232
/// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
187233
///
188234
/// This produces the same result as an `as` cast, but ensures that the bit-width remains

core/src/num/nonzero.rs

+64
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,70 @@ macro_rules! nonzero_integer {
605605
}
606606
}
607607

608+
/// Returns `self` with only the most significant bit set.
609+
///
610+
/// # Example
611+
///
612+
/// Basic usage:
613+
///
614+
/// ```
615+
/// #![feature(isolate_most_least_significant_one)]
616+
///
617+
/// # use core::num::NonZero;
618+
/// # fn main() { test().unwrap(); }
619+
/// # fn test() -> Option<()> {
620+
#[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")]
621+
#[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_01000000)?;")]
622+
///
623+
/// assert_eq!(a.isolate_most_significant_one(), b);
624+
/// # Some(())
625+
/// # }
626+
/// ```
627+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
628+
#[must_use = "this returns the result of the operation, \
629+
without modifying the original"]
630+
#[inline(always)]
631+
pub const fn isolate_most_significant_one(self) -> Self {
632+
let n = self.get() & (((1 as $Int) << (<$Int>::BITS - 1)).wrapping_shr(self.leading_zeros()));
633+
634+
// SAFETY:
635+
// `self` is non-zero, so masking to preserve only the most
636+
// significant set bit will result in a non-zero `n`.
637+
unsafe { NonZero::new_unchecked(n) }
638+
}
639+
640+
/// Returns `self` with only the least significant bit set.
641+
///
642+
/// # Example
643+
///
644+
/// Basic usage:
645+
///
646+
/// ```
647+
/// #![feature(isolate_most_least_significant_one)]
648+
///
649+
/// # use core::num::NonZero;
650+
/// # fn main() { test().unwrap(); }
651+
/// # fn test() -> Option<()> {
652+
#[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")]
653+
#[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_00000100)?;")]
654+
///
655+
/// assert_eq!(a.isolate_least_significant_one(), b);
656+
/// # Some(())
657+
/// # }
658+
/// ```
659+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
660+
#[must_use = "this returns the result of the operation, \
661+
without modifying the original"]
662+
#[inline(always)]
663+
pub const fn isolate_least_significant_one(self) -> Self {
664+
let n = self.get();
665+
let n = n & n.wrapping_neg();
666+
667+
// SAFETY: `self` is non-zero, so `self` with only its least
668+
// significant set bit will remain non-zero.
669+
unsafe { NonZero::new_unchecked(n) }
670+
}
671+
608672
/// Returns the number of ones in the binary representation of `self`.
609673
///
610674
/// # Examples

core/src/num/uint_macros.rs

+46
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,52 @@ macro_rules! uint_impl {
213213
(!self).trailing_zeros()
214214
}
215215

216+
/// Returns `self` with only the most significant bit set, or `0` if
217+
/// the input is `0`.
218+
///
219+
/// # Examples
220+
///
221+
/// Basic usage:
222+
///
223+
/// ```
224+
/// #![feature(isolate_most_least_significant_one)]
225+
///
226+
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
227+
///
228+
/// assert_eq!(n.isolate_most_significant_one(), 0b_01000000);
229+
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")]
230+
/// ```
231+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
232+
#[must_use = "this returns the result of the operation, \
233+
without modifying the original"]
234+
#[inline(always)]
235+
pub const fn isolate_most_significant_one(self) -> Self {
236+
self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros()))
237+
}
238+
239+
/// Returns `self` with only the least significant bit set, or `0` if
240+
/// the input is `0`.
241+
///
242+
/// # Examples
243+
///
244+
/// Basic usage:
245+
///
246+
/// ```
247+
/// #![feature(isolate_most_least_significant_one)]
248+
///
249+
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")]
250+
///
251+
/// assert_eq!(n.isolate_least_significant_one(), 0b_00000100);
252+
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")]
253+
/// ```
254+
#[unstable(feature = "isolate_most_least_significant_one", issue = "136909")]
255+
#[must_use = "this returns the result of the operation, \
256+
without modifying the original"]
257+
#[inline(always)]
258+
pub const fn isolate_least_significant_one(self) -> Self {
259+
self & self.wrapping_neg()
260+
}
261+
216262
/// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size.
217263
///
218264
/// This produces the same result as an `as` cast, but ensures that the bit-width remains

coretests/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#![feature(ip)]
4545
#![feature(ip_from)]
4646
#![feature(is_ascii_octdigit)]
47+
#![feature(isolate_most_least_significant_one)]
4748
#![feature(iter_advance_by)]
4849
#![feature(iter_array_chunks)]
4950
#![feature(iter_chain)]

coretests/tests/nonzero.rs

+100
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,106 @@ fn nonzero_trailing_zeros() {
321321
assert_eq!(TRAILING_ZEROS, 2);
322322
}
323323

324+
#[test]
325+
fn test_nonzero_isolate_most_significant_one() {
326+
// Signed most significant one
327+
macro_rules! nonzero_int_impl {
328+
($($T:ty),+) => {
329+
$(
330+
{
331+
const BITS: $T = -1;
332+
const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
333+
334+
// Right shift the most significant one through each
335+
// bit position, starting with all bits set
336+
let mut i = 0;
337+
while i < <$T>::BITS {
338+
assert_eq!(
339+
NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(),
340+
NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one()
341+
);
342+
i += 1;
343+
}
344+
}
345+
)+
346+
};
347+
}
348+
349+
// Unsigned most significant one
350+
macro_rules! nonzero_uint_impl {
351+
($($T:ty),+) => {
352+
$(
353+
{
354+
const BITS: $T = <$T>::MAX;
355+
const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
356+
357+
let mut i = 0;
358+
while i < <$T>::BITS {
359+
assert_eq!(
360+
NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(),
361+
NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one(),
362+
);
363+
i += 1;
364+
}
365+
}
366+
)+
367+
};
368+
}
369+
370+
nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
371+
nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
372+
}
373+
374+
#[test]
375+
fn test_nonzero_isolate_least_significant_one() {
376+
// Signed least significant one
377+
macro_rules! nonzero_int_impl {
378+
($($T:ty),+) => {
379+
$(
380+
{
381+
const BITS: $T = -1;
382+
const LEAST_SIG_ONE: $T = 1;
383+
384+
// Left shift the least significant one through each
385+
// bit position, starting with all bits set
386+
let mut i = 0;
387+
while i < <$T>::BITS {
388+
assert_eq!(
389+
NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(),
390+
NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one()
391+
);
392+
i += 1;
393+
}
394+
}
395+
)+
396+
};
397+
}
398+
399+
// Unsigned least significant one
400+
macro_rules! nonzero_uint_impl {
401+
($($T:ty),+) => {
402+
$(
403+
{
404+
const BITS: $T = <$T>::MAX;
405+
const LEAST_SIG_ONE: $T = 1;
406+
407+
let mut i = 0;
408+
while i < <$T>::BITS {
409+
assert_eq!(
410+
NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(),
411+
NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one(),
412+
);
413+
i += 1;
414+
}
415+
}
416+
)+
417+
};
418+
}
419+
420+
nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
421+
nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
422+
}
423+
324424
#[test]
325425
fn test_nonzero_uint_div() {
326426
let nz = NonZero::new(1).unwrap();

coretests/tests/num/int_macros.rs

+34
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,40 @@ macro_rules! int_module {
192192
}
193193
}
194194

195+
#[test]
196+
fn test_isolate_most_significant_one() {
197+
const BITS: $T = -1;
198+
const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
199+
200+
// Right shift the most significant one through each
201+
// bit position, starting with all bits set
202+
let mut i = 0;
203+
while i < <$T>::BITS {
204+
assert_eq!(
205+
(BITS >> i).isolate_most_significant_one(),
206+
(MOST_SIG_ONE >> i).isolate_most_significant_one()
207+
);
208+
i += 1;
209+
}
210+
}
211+
212+
#[test]
213+
fn test_isolate_least_significant_one() {
214+
const BITS: $T = -1;
215+
const LEAST_SIG_ONE: $T = 1;
216+
217+
// Left shift the least significant one through each
218+
// bit position, starting with all bits set
219+
let mut i = 0;
220+
while i < <$T>::BITS {
221+
assert_eq!(
222+
(BITS << i).isolate_least_significant_one(),
223+
(LEAST_SIG_ONE << i).isolate_least_significant_one()
224+
);
225+
i += 1;
226+
}
227+
}
228+
195229
#[test]
196230
fn test_from_str() {
197231
fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {

coretests/tests/num/uint_macros.rs

+34
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,40 @@ macro_rules! uint_module {
141141
}
142142
}
143143

144+
#[test]
145+
fn test_isolate_most_significant_one() {
146+
const BITS: $T = <$T>::MAX;
147+
const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1);
148+
149+
// Right shift the most significant one through each
150+
// bit position, starting with all bits set
151+
let mut i = 0;
152+
while i < <$T>::BITS {
153+
assert_eq!(
154+
(BITS >> i).isolate_most_significant_one(),
155+
(MOST_SIG_ONE >> i).isolate_most_significant_one(),
156+
);
157+
i += 1;
158+
}
159+
}
160+
161+
#[test]
162+
fn test_isolate_least_significant_one() {
163+
const BITS: $T = <$T>::MAX;
164+
const LEAST_SIG_ONE: $T = 1;
165+
166+
// Left shift the least significant one through each
167+
// bit position, starting with all bits set
168+
let mut i = 0;
169+
while i < <$T>::BITS {
170+
assert_eq!(
171+
(BITS << i).isolate_least_significant_one(),
172+
(LEAST_SIG_ONE << i).isolate_least_significant_one(),
173+
);
174+
i += 1;
175+
}
176+
}
177+
144178
fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> {
145179
core::str::FromStr::from_str(t).ok()
146180
}

0 commit comments

Comments
 (0)