diff options
| author | bors <bors@rust-lang.org> | 2021-07-07 03:31:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-07-07 03:31:23 +0000 |
| commit | c5e344f7747dbd7e7d4b209e3c480deb5979a56f (patch) | |
| tree | 0390ebc50ec6f445460fefd566a67be3be79a088 /library/core | |
| parent | c0bd5a584da4f26a1391163a0bdc21b34cf1ba54 (diff) | |
| parent | 51968854f4c3bd9cc54cf35c3e84047adfc6cf21 (diff) | |
| download | rust-c5e344f7747dbd7e7d4b209e3c480deb5979a56f.tar.gz rust-c5e344f7747dbd7e7d4b209e3c480deb5979a56f.zip | |
Auto merge of #86920 - JohnTitor:rollup-buvzpkr, r=JohnTitor
Rollup of 8 pull requests
Successful merges:
- #80918 (Add Integer::log variants)
- #86717 (Rename some Rust 2021 lints to better names )
- #86819 (Clean up rustdoc IDs)
- #86880 (Test ManuallyDrop::clone_from.)
- #86906 (Replace deprecated compare_and_swap and fix typo in core::sync::atomic::{fence, compiler_fence} docs)
- #86907 (Migrate `cpu-usage-over-time.py` to Python 3)
- #86916 (rewrote documentation for thread::yield_now())
- #86919 (Update books)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/core')
| -rw-r--r-- | library/core/src/lib.rs | 3 | ||||
| -rw-r--r-- | library/core/src/num/int_macros.rs | 188 | ||||
| -rw-r--r-- | library/core/src/num/uint_macros.rs | 188 | ||||
| -rw-r--r-- | library/core/src/sync/atomic.rs | 8 | ||||
| -rw-r--r-- | library/core/tests/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/tests/manually_drop.rs | 8 | ||||
| -rw-r--r-- | library/core/tests/num/int_log.rs | 99 | ||||
| -rw-r--r-- | library/core/tests/num/mod.rs | 1 |
8 files changed, 493 insertions, 3 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 866cd5ec535..3557dbad90c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -164,7 +164,8 @@ #![feature(no_niche)] // rust-lang/rust#68303 #![feature(no_coverage)] // rust-lang/rust#84605 #![deny(unsafe_op_in_unsafe_fn)] -#![deny(or_patterns_back_compat)] +#![cfg_attr(bootstrap, deny(or_patterns_back_compat))] +#![cfg_attr(not(bootstrap), deny(rust_2021_incompatible_or_patterns))] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2e466106fe5..a9461649d4a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1744,6 +1744,194 @@ macro_rules! int_impl { } } + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// This method may not be optimized owing to implementation details; + /// `log2` can produce results more efficiently for base 2, and `log10` + /// can produce results more efficiently for base 10. + /// + /// # Panics + /// + /// When the number is zero, or if the base is not at least 2; it + /// panics in debug mode and the return value is wrapped to 0 in release + /// mode (the only situation in which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log(self, base: Self) -> Self { + match self.checked_log(base) { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Panics + /// + /// When the number is zero it panics in debug mode and the return value + /// is wrapped to 0 in release mode (the only situation in which the + /// method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log2(self) -> Self { + match self.checked_log2() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Panics + /// + /// When the number is zero it panics in debug mode and the return value + /// is wrapped to 0 in release mode (the only situation in which the + /// method can return 0). + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log10(self) -> Self { + match self.checked_log10() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// Returns `None` if the number is negative or zero, or if the base is not at least 2. + /// + /// This method may not be optimized owing to implementation details; + /// `checked_log2` can produce results more efficiently for base 2, and + /// `checked_log10` can produce results more efficiently for base 10. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log(self, base: Self) -> Option<Self> { + if self <= 0 || base <= 1 { + None + } else { + let mut n = 0; + let mut r = self; + + // Optimization for 128 bit wide integers. + if Self::BITS == 128 { + let b = Self::log2(self) / (Self::log2(base) + 1); + n += b; + r /= base.pow(b as u32); + } + + while r >= base { + r /= base; + n += 1; + } + Some(n) + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// Returns `None` if the number is negative or zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log2(self) -> Option<Self> { + if self <= 0 { + None + } else { + // SAFETY: We just checked that this number is positive + let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + Some(log) + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// Returns `None` if the number is negative or zero. + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log10(self) -> Option<Self> { + self.checked_log(10) + } + /// Computes the absolute value of `self`. /// /// # Overflow behavior diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e512d90ef37..bf4d2e7433e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -634,6 +634,194 @@ macro_rules! uint_impl { } } + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// This method may not be optimized owing to implementation details; + /// `log2` can produce results more efficiently for base 2, and `log10` + /// can produce results more efficiently for base 10. + /// + /// # Panics + /// + /// When the number is negative, zero, or if the base is not at least 2; + /// it panics in debug mode and the return value is wrapped to 0 in + /// release mode (the only situation in which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log(self, base: Self) -> Self { + match self.checked_log(base) { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Panics + /// + /// When the number is negative or zero it panics in debug mode and + /// the return value is wrapped to 0 in release mode (the only situation in + /// which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log2(self) -> Self { + match self.checked_log2() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Panics + /// + /// When the number is negative or zero it panics in debug mode and the + /// return value is wrapped to 0 in release mode (the only situation in + /// which the method can return 0). + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log10(self) -> Self { + match self.checked_log10() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// Returns `None` if the number is zero, or if the base is not at least 2. + /// + /// This method may not be optimized owing to implementation details; + /// `checked_log2` can produce results more efficiently for base 2, and + /// `checked_log10` can produce results more efficiently for base 10. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log(self, base: Self) -> Option<Self> { + if self <= 0 || base <= 1 { + None + } else { + let mut n = 0; + let mut r = self; + + // Optimization for 128 bit wide integers. + if Self::BITS == 128 { + let b = Self::log2(self) / (Self::log2(base) + 1); + n += b; + r /= base.pow(b as u32); + } + + while r >= base { + r /= base; + n += 1; + } + Some(n) + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// Returns `None` if the number is zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log2(self) -> Option<Self> { + if self <= 0 { + None + } else { + // SAFETY: We just checked that this number is positive + let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + Some(log) + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// Returns `None` if the number is zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log10(self) -> Option<Self> { + self.checked_log(10) + } + /// Checked negation. Computes `-self`, returning `None` unless `self == /// 0`. /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index f1a115563fd..b673b36c102 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2648,7 +2648,11 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// /// pub fn lock(&self) { /// // Wait until the old value is `false`. -/// while self.flag.compare_and_swap(false, true, Ordering::Relaxed) != false {} +/// while self +/// .flag +/// .compare_exchange_weak(false, true, Ordering::Relaxed, Ordering::Relaxed) +/// .is_err() +/// {} /// // This fence synchronizes-with store in `unlock`. /// fence(Ordering::Acquire); /// } @@ -2710,7 +2714,7 @@ pub fn fence(order: Ordering) { /// Without `compiler_fence`, the `assert_eq!` in following code /// is *not* guaranteed to succeed, despite everything happening in a single thread. /// To see why, remember that the compiler is free to swap the stores to -/// `IMPORTANT_VARIABLE` and `IS_READ` since they are both +/// `IMPORTANT_VARIABLE` and `IS_READY` since they are both /// `Ordering::Relaxed`. If it does, and the signal handler is invoked right /// after `IS_READY` is updated, then the signal handler will see /// `IS_READY=1`, but `IMPORTANT_VARIABLE=0`. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f9d331063f4..cc4ff1be563 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(try_trait_v2)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] +#![feature(int_log)] #![feature(iter_advance_by)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] diff --git a/library/core/tests/manually_drop.rs b/library/core/tests/manually_drop.rs index 77a338daf7d..9eac279733a 100644 --- a/library/core/tests/manually_drop.rs +++ b/library/core/tests/manually_drop.rs @@ -2,6 +2,7 @@ use core::mem::ManuallyDrop; #[test] fn smoke() { + #[derive(Clone)] struct TypeWithDrop; impl Drop for TypeWithDrop { fn drop(&mut self) { @@ -16,4 +17,11 @@ fn smoke() { let x: Box<ManuallyDrop<[TypeWithDrop]>> = Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop])); drop(x); + + // test clone and clone_from implementations + let mut x = ManuallyDrop::new(TypeWithDrop); + let y = x.clone(); + x.clone_from(&y); + drop(x); + drop(y); } diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs new file mode 100644 index 00000000000..99a9b17ab11 --- /dev/null +++ b/library/core/tests/num/int_log.rs @@ -0,0 +1,99 @@ +//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a +//! separate file because there's both a large number of them, and not all tests +//! can be run on Android. This is because in Android `log2` uses an imprecise +//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53 + +#[test] +fn checked_log() { + assert_eq!(999u32.checked_log(10), Some(2)); + assert_eq!(1000u32.checked_log(10), Some(3)); + assert_eq!(555u32.checked_log(13), Some(2)); + assert_eq!(63u32.checked_log(4), Some(2)); + assert_eq!(64u32.checked_log(4), Some(3)); + assert_eq!(10460353203u64.checked_log(3), Some(21)); + assert_eq!(10460353202u64.checked_log(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7)); + + assert_eq!(0u8.checked_log(4), None); + assert_eq!(0u16.checked_log(4), None); + assert_eq!(0i8.checked_log(4), None); + assert_eq!(0i16.checked_log(4), None); + + for i in i16::MIN..=0 { + assert_eq!(i.checked_log(4), None); + } + for i in 1..=i16::MAX { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as i16)); + } + for i in 1..=u16::MAX { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u16)); + } +} + +#[test] +fn checked_log2() { + assert_eq!(5u32.checked_log2(), Some(2)); + assert_eq!(0u64.checked_log2(), None); + assert_eq!(128i32.checked_log2(), Some(7)); + assert_eq!((-55i16).checked_log2(), None); + + assert_eq!(0u8.checked_log2(), None); + assert_eq!(0u16.checked_log2(), None); + assert_eq!(0i8.checked_log2(), None); + assert_eq!(0i16.checked_log2(), None); + + for i in 1..=u8::MAX { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u8)); + } + for i in 1..=u16::MAX { + // Guard against Android's imprecise f32::log2 implementation. + if i != 8192 && i != 32768 { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u16)); + } + } + for i in i8::MIN..=0 { + assert_eq!(i.checked_log2(), None); + } + for i in 1..=i8::MAX { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as i8)); + } + for i in i16::MIN..=0 { + assert_eq!(i.checked_log2(), None); + } + for i in 1..=i16::MAX { + // Guard against Android's imprecise f32::log2 implementation. + if i != 8192 { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as i16)); + } + } +} + +// Validate cases that fail on Android's imprecise float log2 implementation. +#[test] +#[cfg(not(target_os = "android"))] +fn checked_log2_not_android() { + assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u16)); + assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u16)); + assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as i16)); +} + +#[test] +fn checked_log10() { + assert_eq!(0u8.checked_log10(), None); + assert_eq!(0u16.checked_log10(), None); + assert_eq!(0i8.checked_log10(), None); + assert_eq!(0i16.checked_log10(), None); + + for i in i16::MIN..=0 { + assert_eq!(i.checked_log10(), None); + } + for i in 1..=i16::MAX { + assert_eq!(i.checked_log10(), Some((i as f32).log10() as i16)); + } + for i in 1..=u16::MAX { + assert_eq!(i.checked_log10(), Some((i as f32).log10() as u16)); + } +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index bbb67667dfc..76e838cf6bf 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -29,6 +29,7 @@ mod u8; mod bignum; mod dec2flt; mod flt2dec; +mod int_log; mod ops; mod wrapping; |
