Skip to content

Commit 126d88b

Browse files
authored
Rollup merge of #79114 - andjo403:nonzero_leading_trailing_zeros, r=m-ou-se
add trailing_zeros and leading_zeros to non zero types as a way towards being able to use the optimized intrinsics ctlz_nonzero and cttz_nonzero from stable. have not crated any tracking issue if this is not a solution that is wanted
2 parents f85c3f7 + 9bbc4c1 commit 126d88b

File tree

4 files changed

+178
-1
lines changed

4 files changed

+178
-1
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#![feature(const_mut_refs)]
8181
#![feature(const_int_pow)]
8282
#![feature(constctlz)]
83+
#![feature(const_cttz)]
8384
#![feature(const_panic)]
8485
#![feature(const_pin)]
8586
#![feature(const_fn)]

library/core/src/num/nonzero.rs

+74
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::str::FromStr;
66

77
use super::from_str_radix;
88
use super::{IntErrorKind, ParseIntError};
9+
use crate::intrinsics;
910

1011
macro_rules! doc_comment {
1112
($x:expr, $($tt:tt)*) => {
@@ -189,3 +190,76 @@ macro_rules! from_str_radix_nzint_impl {
189190

190191
from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
191192
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
193+
194+
macro_rules! nonzero_leading_trailing_zeros {
195+
( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
196+
$(
197+
impl $Ty {
198+
doc_comment! {
199+
concat!("Returns the number of leading zeros in the binary representation of `self`.
200+
201+
On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided.
202+
203+
# Examples
204+
205+
Basic usage:
206+
207+
```
208+
#![feature(nonzero_leading_trailing_zeros)]
209+
let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();
210+
211+
assert_eq!(n.leading_zeros(), 0);
212+
```"),
213+
#[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
214+
#[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
215+
#[inline]
216+
pub const fn leading_zeros(self) -> u32 {
217+
// SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero
218+
unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 }
219+
}
220+
}
221+
222+
doc_comment! {
223+
concat!("Returns the number of trailing zeros in the binary representation
224+
of `self`.
225+
226+
On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided.
227+
228+
# Examples
229+
230+
Basic usage:
231+
232+
```
233+
#![feature(nonzero_leading_trailing_zeros)]
234+
let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();
235+
236+
assert_eq!(n.trailing_zeros(), 3);
237+
```"),
238+
#[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
239+
#[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")]
240+
#[inline]
241+
pub const fn trailing_zeros(self) -> u32 {
242+
// SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
243+
unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 }
244+
}
245+
}
246+
247+
}
248+
)+
249+
}
250+
}
251+
252+
nonzero_leading_trailing_zeros! {
253+
NonZeroU8(u8), u8::MAX;
254+
NonZeroU16(u16), u16::MAX;
255+
NonZeroU32(u32), u32::MAX;
256+
NonZeroU64(u64), u64::MAX;
257+
NonZeroU128(u128), u128::MAX;
258+
NonZeroUsize(usize), usize::MAX;
259+
NonZeroI8(u8), -1i8;
260+
NonZeroI16(u16), -1i16;
261+
NonZeroI32(u32), -1i32;
262+
NonZeroI64(u64), -1i64;
263+
NonZeroI128(u128), -1i128;
264+
NonZeroIsize(usize), -1isize;
265+
}

library/core/tests/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#![feature(once_cell)]
6161
#![feature(unsafe_block_in_unsafe_fn)]
6262
#![feature(int_bits_const)]
63+
#![feature(nonzero_leading_trailing_zeros)]
64+
#![feature(const_option)]
6365
#![deny(unsafe_op_in_unsafe_fn)]
6466

6567
extern crate test;

library/core/tests/nonzero.rs

+101-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use core::convert::TryFrom;
2-
use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
2+
use core::num::{
3+
IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
4+
NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
5+
};
36
use core::option::Option::{self, None, Some};
47
use std::mem::size_of;
58

@@ -212,3 +215,100 @@ fn nonzero_const() {
212215
const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
213216
assert!(ONE.is_some());
214217
}
218+
219+
#[test]
220+
fn nonzero_leading_zeros() {
221+
assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7);
222+
assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7);
223+
assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15);
224+
assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15);
225+
assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31);
226+
assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31);
227+
assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63);
228+
assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63);
229+
assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127);
230+
assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127);
231+
assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
232+
assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
233+
234+
assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
235+
assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
236+
assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
237+
assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
238+
assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
239+
assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
240+
assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
241+
assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
242+
assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
243+
assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
244+
assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
245+
assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
246+
247+
assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0);
248+
assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0);
249+
assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0);
250+
assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0);
251+
assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0);
252+
assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0);
253+
assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0);
254+
assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0);
255+
assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0);
256+
assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0);
257+
assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0);
258+
assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0);
259+
260+
const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros();
261+
assert_eq!(LEADING_ZEROS, 15);
262+
}
263+
264+
#[test]
265+
fn nonzero_trailing_zeros() {
266+
assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0);
267+
assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0);
268+
assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0);
269+
assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0);
270+
assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0);
271+
assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0);
272+
assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0);
273+
assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0);
274+
assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0);
275+
assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0);
276+
assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0);
277+
assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0);
278+
279+
assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2);
280+
assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2);
281+
assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2);
282+
assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2);
283+
assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2);
284+
assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2);
285+
assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2);
286+
assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2);
287+
assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2);
288+
assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2);
289+
assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2);
290+
assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2);
291+
292+
assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7);
293+
assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7);
294+
assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15);
295+
assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15);
296+
assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31);
297+
assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31);
298+
assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63);
299+
assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63);
300+
assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127);
301+
assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127);
302+
303+
assert_eq!(
304+
NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
305+
usize::BITS - 1
306+
);
307+
assert_eq!(
308+
NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
309+
usize::BITS - 1
310+
);
311+
312+
const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
313+
assert_eq!(TRAILING_ZEROS, 2);
314+
}

0 commit comments

Comments
 (0)