diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 41202546566a7..d67f9c15a1916 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -80,6 +80,7 @@ #![feature(const_mut_refs)] #![feature(const_int_pow)] #![feature(constctlz)] +#![feature(const_cttz)] #![feature(const_panic)] #![feature(const_pin)] #![feature(const_fn)] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5a9fd902c9ca1..716b4a90e5ec2 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -6,6 +6,7 @@ use crate::str::FromStr; use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; +use crate::intrinsics; macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { @@ -189,3 +190,76 @@ macro_rules! from_str_radix_nzint_impl { from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } + +macro_rules! nonzero_leading_trailing_zeros { + ( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => { + $( + impl $Ty { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +On many architectures, this function can perform better than `leading_zeros()` on the underlying integer type, as special handling of zero can be avoided. + +# Examples + +Basic usage: + +``` +#![feature(nonzero_leading_trailing_zeros)] +let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap(); + +assert_eq!(n.leading_zeros(), 0); +```"), + #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero + unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 } + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +On many architectures, this function can perform better than `trailing_zeros()` on the underlying integer type, as special handling of zero can be avoided. + +# Examples + +Basic usage: + +``` +#![feature(nonzero_leading_trailing_zeros)] +let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap(); + +assert_eq!(n.trailing_zeros(), 3); +```"), + #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero + unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 } + } + } + + } + )+ + } +} + +nonzero_leading_trailing_zeros! { + NonZeroU8(u8), u8::MAX; + NonZeroU16(u16), u16::MAX; + NonZeroU32(u32), u32::MAX; + NonZeroU64(u64), u64::MAX; + NonZeroU128(u128), u128::MAX; + NonZeroUsize(usize), usize::MAX; + NonZeroI8(u8), -1i8; + NonZeroI16(u16), -1i16; + NonZeroI32(u32), -1i32; + NonZeroI64(u64), -1i64; + NonZeroI128(u128), -1i128; + NonZeroIsize(usize), -1isize; +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c9f9b890c3938..14ef03fd53eba 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -60,6 +60,8 @@ #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] #![feature(int_bits_const)] +#![feature(nonzero_leading_trailing_zeros)] +#![feature(const_option)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index fb1293c99bba9..ca449b4350ede 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -1,5 +1,8 @@ use core::convert::TryFrom; -use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8}; +use core::num::{ + IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, + NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; use core::option::Option::{self, None, Some}; use std::mem::size_of; @@ -212,3 +215,100 @@ fn nonzero_const() { const ONE: Option = NonZeroU8::new(1); assert!(ONE.is_some()); } + +#[test] +fn nonzero_leading_zeros() { + assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1); + assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1); + + assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2); + + assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0); + + const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros(); + assert_eq!(LEADING_ZEROS, 15); +} + +#[test] +fn nonzero_trailing_zeros() { + assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0); + + assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2); + + assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127); + assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127); + + assert_eq!( + NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + assert_eq!( + NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + + const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros(); + assert_eq!(TRAILING_ZEROS, 2); +}