about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2021-01-16 19:27:51 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2021-01-16 19:27:51 -0800
commit3e16e9211ef7eff4d421f384140e729df1120372 (patch)
treea74213915efb1c110b7fde4f96b70c13978e49d3
parent6c869d34ae2d87d21db9892d4dc088639bcbe041 (diff)
downloadrust-3e16e9211ef7eff4d421f384140e729df1120372.tar.gz
rust-3e16e9211ef7eff4d421f384140e729df1120372.zip
Add NonZeroUn::is_power_of_two
This saves instructions on both new and old machines.
-rw-r--r--library/core/src/num/nonzero.rs40
1 files changed, 40 insertions, 0 deletions
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index ba8918b192f..111feb7dbec 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -286,3 +286,43 @@ nonzero_integers_div! {
     NonZeroU128(u128);
     NonZeroUsize(usize);
 }
+
+macro_rules! nonzero_unsigned_is_power_of_two {
+    ( $( $Ty: ident )+ ) => {
+        $(
+            impl $Ty {
+
+                /// Returns `true` if and only if `self == (1 << k)` for some `k`.
+                ///
+                /// On many architectures, this function can perform better than `is_power_of_two()`
+                /// on the underlying integer type, as special handling of zero can be avoided.
+                ///
+                /// # Examples
+                ///
+                /// Basic usage:
+                ///
+                /// ```
+                /// #![feature(nonzero_is_power_of_two)]
+                ///
+                #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
+                /// assert!(eight.is_power_of_two());
+                #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
+                /// assert!(!ten.is_power_of_two());
+                /// ```
+                #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
+                #[inline]
+                pub const fn is_power_of_two(self) -> bool {
+                    // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
+                    // On the basic x86-64 target, this saves 3 instructions for the zero check.
+                    // On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction
+                    // compared to the `POPCNT` implementation on the underlying integer type.
+
+                    intrinsics::ctpop(self.get()) < 2
+                }
+
+            }
+        )+
+    }
+}
+
+nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }