Skip to content

Commit 8743ccf

Browse files
authored
Unrolled build for #145381
Rollup merge of #145381 - Gnurou:int_lowest_highest_one, r=jhpratt Implement feature `int_lowest_highest_one` for integer and NonZero types Tracking issue: #145203 Implement the accepted ACP #145203 for methods that find the index of the least significant (lowest) and most significant (highest) set bit in an integer for signed, unsigned, and NonZero types. Also add unit tests for all these types.
2 parents f605b57 + 73d3d28 commit 8743ccf

File tree

7 files changed

+321
-0
lines changed

7 files changed

+321
-0
lines changed

library/core/src/num/int_macros.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,48 @@ macro_rules! int_impl {
209209
self & self.wrapping_neg()
210210
}
211211

212+
/// Returns the index of the highest bit set to one in `self`, or `None`
213+
/// if `self` is `0`.
214+
///
215+
/// # Examples
216+
///
217+
/// ```
218+
/// #![feature(int_lowest_highest_one)]
219+
///
220+
#[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")]
221+
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")]
222+
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")]
223+
#[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")]
224+
/// ```
225+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
226+
#[must_use = "this returns the result of the operation, \
227+
without modifying the original"]
228+
#[inline(always)]
229+
pub const fn highest_one(self) -> Option<u32> {
230+
(self as $UnsignedT).highest_one()
231+
}
232+
233+
/// Returns the index of the lowest bit set to one in `self`, or `None`
234+
/// if `self` is `0`.
235+
///
236+
/// # Examples
237+
///
238+
/// ```
239+
/// #![feature(int_lowest_highest_one)]
240+
///
241+
#[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")]
242+
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
243+
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")]
244+
#[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")]
245+
/// ```
246+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
247+
#[must_use = "this returns the result of the operation, \
248+
without modifying the original"]
249+
#[inline(always)]
250+
pub const fn lowest_one(self) -> Option<u32> {
251+
(self as $UnsignedT).lowest_one()
252+
}
253+
212254
/// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
213255
///
214256
/// This produces the same result as an `as` cast, but ensures that the bit-width remains

library/core/src/num/nonzero.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,54 @@ macro_rules! nonzero_integer {
681681
unsafe { NonZero::new_unchecked(n) }
682682
}
683683

684+
/// Returns the index of the highest bit set to one in `self`.
685+
///
686+
/// # Examples
687+
///
688+
/// ```
689+
/// #![feature(int_lowest_highest_one)]
690+
///
691+
/// # use core::num::NonZero;
692+
/// # fn main() { test().unwrap(); }
693+
/// # fn test() -> Option<()> {
694+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.highest_one(), 0);")]
695+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.highest_one(), 4);")]
696+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.highest_one(), 4);")]
697+
/// # Some(())
698+
/// # }
699+
/// ```
700+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
701+
#[must_use = "this returns the result of the operation, \
702+
without modifying the original"]
703+
#[inline(always)]
704+
pub const fn highest_one(self) -> u32 {
705+
Self::BITS - 1 - self.leading_zeros()
706+
}
707+
708+
/// Returns the index of the lowest bit set to one in `self`.
709+
///
710+
/// # Examples
711+
///
712+
/// ```
713+
/// #![feature(int_lowest_highest_one)]
714+
///
715+
/// # use core::num::NonZero;
716+
/// # fn main() { test().unwrap(); }
717+
/// # fn test() -> Option<()> {
718+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.lowest_one(), 0);")]
719+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.lowest_one(), 4);")]
720+
#[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.lowest_one(), 0);")]
721+
/// # Some(())
722+
/// # }
723+
/// ```
724+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
725+
#[must_use = "this returns the result of the operation, \
726+
without modifying the original"]
727+
#[inline(always)]
728+
pub const fn lowest_one(self) -> u32 {
729+
self.trailing_zeros()
730+
}
731+
684732
/// Returns the number of ones in the binary representation of `self`.
685733
///
686734
/// # Examples

library/core/src/num/uint_macros.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,54 @@ macro_rules! uint_impl {
261261
self & self.wrapping_neg()
262262
}
263263

264+
/// Returns the index of the highest bit set to one in `self`, or `None`
265+
/// if `self` is `0`.
266+
///
267+
/// # Examples
268+
///
269+
/// ```
270+
/// #![feature(int_lowest_highest_one)]
271+
///
272+
#[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")]
273+
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")]
274+
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")]
275+
#[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")]
276+
/// ```
277+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
278+
#[must_use = "this returns the result of the operation, \
279+
without modifying the original"]
280+
#[inline(always)]
281+
pub const fn highest_one(self) -> Option<u32> {
282+
match NonZero::new(self) {
283+
Some(v) => Some(v.highest_one()),
284+
None => None,
285+
}
286+
}
287+
288+
/// Returns the index of the lowest bit set to one in `self`, or `None`
289+
/// if `self` is `0`.
290+
///
291+
/// # Examples
292+
///
293+
/// ```
294+
/// #![feature(int_lowest_highest_one)]
295+
///
296+
#[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")]
297+
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
298+
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")]
299+
#[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")]
300+
/// ```
301+
#[unstable(feature = "int_lowest_highest_one", issue = "145203")]
302+
#[must_use = "this returns the result of the operation, \
303+
without modifying the original"]
304+
#[inline(always)]
305+
pub const fn lowest_one(self) -> Option<u32> {
306+
match NonZero::new(self) {
307+
Some(v) => Some(v.lowest_one()),
308+
None => None,
309+
}
310+
}
311+
264312
/// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size.
265313
///
266314
/// This produces the same result as an `as` cast, but ensures that the bit-width remains

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#![feature(generic_assert_internals)]
5555
#![feature(hasher_prefixfree_extras)]
5656
#![feature(hashmap_internals)]
57+
#![feature(int_lowest_highest_one)]
5758
#![feature(int_roundings)]
5859
#![feature(ip)]
5960
#![feature(is_ascii_octdigit)]

library/coretests/tests/nonzero.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,111 @@ fn test_nonzero_fmt() {
462462

463463
assert_eq!(i, nz);
464464
}
465+
466+
#[test]
467+
fn test_nonzero_highest_one() {
468+
macro_rules! nonzero_int_impl {
469+
($($T:ty),+) => {
470+
$(
471+
{
472+
for i in 0..<$T>::BITS {
473+
// Set single bit.
474+
assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i);
475+
if i > <$T>::BITS {
476+
// Set lowest bits.
477+
assert_eq!(
478+
NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(),
479+
<$T>::BITS - i - 2,
480+
);
481+
}
482+
// Set highest bits.
483+
assert_eq!(
484+
NonZero::<$T>::new(-1 << i).unwrap().highest_one(),
485+
<$T>::BITS - 1,
486+
);
487+
}
488+
}
489+
)+
490+
};
491+
}
492+
493+
macro_rules! nonzero_uint_impl {
494+
($($T:ty),+) => {
495+
$(
496+
{
497+
for i in 0..<$T>::BITS {
498+
// Set single bit.
499+
assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i);
500+
// Set lowest bits.
501+
assert_eq!(
502+
NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(),
503+
<$T>::BITS - i - 1,
504+
);
505+
// Set highest bits.
506+
assert_eq!(
507+
NonZero::<$T>::new(<$T>::MAX << i).unwrap().highest_one(),
508+
<$T>::BITS - 1,
509+
);
510+
}
511+
}
512+
)+
513+
};
514+
}
515+
516+
nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
517+
nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
518+
}
519+
520+
#[test]
521+
fn test_nonzero_lowest_one() {
522+
macro_rules! nonzero_int_impl {
523+
($($T:ty),+) => {
524+
$(
525+
{
526+
for i in 0..<$T>::BITS {
527+
// Set single bit.
528+
assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i);
529+
if i > <$T>::BITS {
530+
// Set lowest bits.
531+
assert_eq!(
532+
NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(),
533+
0,
534+
);
535+
}
536+
// Set highest bits.
537+
assert_eq!(
538+
NonZero::<$T>::new(-1 << i).unwrap().lowest_one(),
539+
i,
540+
);
541+
}
542+
}
543+
)+
544+
};
545+
}
546+
547+
macro_rules! nonzero_uint_impl {
548+
($($T:ty),+) => {
549+
$(
550+
{
551+
for i in 0..<$T>::BITS {
552+
// Set single bit.
553+
assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i);
554+
// Set lowest bits.
555+
assert_eq!(
556+
NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(),
557+
0,
558+
);
559+
// Set highest bits.
560+
assert_eq!(
561+
NonZero::<$T>::new(<$T>::MAX << i).unwrap().lowest_one(),
562+
i,
563+
);
564+
}
565+
}
566+
)+
567+
};
568+
}
569+
570+
nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
571+
nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
572+
}

library/coretests/tests/num/int_macros.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,46 @@ macro_rules! int_module {
227227
}
228228
}
229229

230+
#[test]
231+
fn test_highest_one() {
232+
const ZERO: $T = 0;
233+
const ONE: $T = 1;
234+
const MINUS_ONE: $T = -1;
235+
236+
assert_eq!(ZERO.highest_one(), None);
237+
238+
for i in 0..<$T>::BITS {
239+
// Set single bit.
240+
assert_eq!((ONE << i).highest_one(), Some(i));
241+
if i != <$T>::BITS - 1 {
242+
// Set lowest bits.
243+
assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 2));
244+
}
245+
// Set highest bits.
246+
assert_eq!((MINUS_ONE << i).highest_one(), Some(<$T>::BITS - 1));
247+
}
248+
}
249+
250+
#[test]
251+
fn test_lowest_one() {
252+
const ZERO: $T = 0;
253+
const ONE: $T = 1;
254+
const MINUS_ONE: $T = -1;
255+
256+
assert_eq!(ZERO.lowest_one(), None);
257+
258+
for i in 0..<$T>::BITS {
259+
// Set single bit.
260+
assert_eq!((ONE << i).lowest_one(), Some(i));
261+
if i != <$T>::BITS - 1 {
262+
// Set lowest bits.
263+
assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0));
264+
}
265+
// Set highest bits.
266+
assert_eq!((MINUS_ONE << i).lowest_one(), Some(i));
267+
}
268+
}
269+
230270
#[test]
231271
fn test_from_str() {
232272
fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {

library/coretests/tests/num/uint_macros.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,40 @@ macro_rules! uint_module {
184184
}
185185
}
186186

187+
#[test]
188+
fn test_highest_one() {
189+
const ZERO: $T = 0;
190+
const ONE: $T = 1;
191+
192+
assert_eq!(ZERO.highest_one(), None);
193+
194+
for i in 0..<$T>::BITS {
195+
// Set single bit.
196+
assert_eq!((ONE << i).highest_one(), Some(i));
197+
// Set lowest bits.
198+
assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 1));
199+
// Set highest bits.
200+
assert_eq!((<$T>::MAX << i).highest_one(), Some(<$T>::BITS - 1));
201+
}
202+
}
203+
204+
#[test]
205+
fn test_lowest_one() {
206+
const ZERO: $T = 0;
207+
const ONE: $T = 1;
208+
209+
assert_eq!(ZERO.lowest_one(), None);
210+
211+
for i in 0..<$T>::BITS {
212+
// Set single bit.
213+
assert_eq!((ONE << i).lowest_one(), Some(i));
214+
// Set lowest bits.
215+
assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0));
216+
// Set highest bits.
217+
assert_eq!((<$T>::MAX << i).lowest_one(), Some(i));
218+
}
219+
}
220+
187221
fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> {
188222
core::str::FromStr::from_str(t).ok()
189223
}

0 commit comments

Comments
 (0)