diff --git a/CHANGELOG.md b/CHANGELOG.md index 8316e39b..0a55186a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com These APIs are compatible with strict-provenance on `cfg(miri)`. Otherwise, they are compatible with permissive-provenance. Once `#![feature(strict_provenance_atomic_ptr)]` is stabilized, these APIs will be strict-provenance compatible in all cases from the version in which it is stabilized. +- Provide stable equivalent of [`#![feature(atomic_bool_fetch_not)]`](https://github.com/rust-lang/rust/issues/98485). ([#24](https://github.com/taiki-e/portable-atomic/pull/24)) + + - `AtomicBool::fetch_not` + - Optimize x86_64 128-bit RMWs. ([#22](https://github.com/taiki-e/portable-atomic/pull/22)) - Optimize x86_64 outline-atomics. diff --git a/README.md b/README.md index a56ea848..7cbe1084 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc. - Provide atomic load/store for targets where atomic is not available at all in the standard library. (riscv without A-extension, msp430, avr) - Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, riscv without A-extension, msp430, avr) (optional, [single-core only](#optional-cfg)) -- Provide stable equivalents of the standard library atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108). +- Provide stable equivalents of the standard library atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108), [`AtomicBool::fetch_not`](https://github.com/rust-lang/rust/issues/98485). - Make features that require newer compilers, such as [fetch_max](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [fetch_min](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_min), [fetch_update](https://doc.rust-lang.org/nightly/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+. ## 128-bit atomics support diff --git a/src/lib.rs b/src/lib.rs index 62e56105..c7fd5af7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc. - Provide atomic load/store for targets where atomic is not available at all in the standard library. (riscv without A-extension, msp430, avr) - Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, riscv without A-extension, msp430, avr) (optional, [single-core only](#optional-cfg)) -- Provide stable equivalents of the standard library atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108). +- Provide stable equivalents of the standard library atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108), [`AtomicBool::fetch_not`](https://github.com/rust-lang/rust/issues/98485). - Make features that require newer compilers, such as [fetch_max](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [fetch_min](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_min), [fetch_update](https://doc.rust-lang.org/nightly/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+. ## 128-bit atomics support @@ -778,8 +778,44 @@ impl AtomicBool { self.inner.fetch_xor(val, order) } - // TODO: Add fetch_not once it is stable on std atomic types. - // https://github.com/rust-lang/rust/issues/98485 + /// Logical "not" with a boolean value. + /// + /// Performs a logical "not" operation on the current value, and sets + /// the new value to the result. + /// + /// Returns the previous value. + /// + /// `fetch_not` takes an [`Ordering`] argument which describes the memory ordering + /// of this operation. All ordering modes are possible. Note that using + /// [`Acquire`] makes the store part of this operation [`Relaxed`], and + /// using [`Release`] makes the load part [`Relaxed`]. + /// + /// # Examples + /// + /// ``` + /// use portable_atomic::{AtomicBool, Ordering}; + /// + /// let foo = AtomicBool::new(true); + /// assert_eq!(foo.fetch_not(Ordering::SeqCst), true); + /// assert_eq!(foo.load(Ordering::SeqCst), false); + /// + /// let foo = AtomicBool::new(false); + /// assert_eq!(foo.fetch_not(Ordering::SeqCst), false); + /// assert_eq!(foo.load(Ordering::SeqCst), true); + /// ``` + #[cfg_attr( + portable_atomic_no_cfg_target_has_atomic, + cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core)) + )] + #[cfg_attr( + not(portable_atomic_no_cfg_target_has_atomic), + cfg(any(target_has_atomic = "ptr", portable_atomic_unsafe_assume_single_core)) + )] + #[inline] + pub fn fetch_not(&self, order: Ordering) -> bool { + self.fetch_xor(true, order) + } + // TODO: Add as_mut_ptr once it is stable on std atomic types. // https://github.com/rust-lang/rust/issues/66893 diff --git a/src/tests/helper.rs b/src/tests/helper.rs index d1b8c48e..cb6169da 100644 --- a/src/tests/helper.rs +++ b/src/tests/helper.rs @@ -941,6 +941,19 @@ macro_rules! __test_atomic_bool { assert_eq!(a.load(Ordering::Relaxed), false); } } + #[test] + fn fetch_not() { + let a = <$atomic_type>::new(true); + test_swap_ordering(|order| a.fetch_not(order)); + for order in swap_orderings() { + let a = <$atomic_type>::new(true); + assert_eq!(a.fetch_not(order), true); + assert_eq!(a.load(Ordering::Relaxed), false); + let a = <$atomic_type>::new(false); + assert_eq!(a.fetch_not(order), false); + assert_eq!(a.load(Ordering::Relaxed), true); + } + } mod quickcheck { use super::super::*; use crate::tests::helper::*; @@ -1008,6 +1021,17 @@ macro_rules! __test_atomic_bool { } true } + fn fetch_not(x: bool, y: bool) -> bool { + for order in swap_orderings() { + let a = <$atomic_type>::new(x); + assert_eq!(a.fetch_not(order), x); + assert_eq!(a.load(Ordering::Relaxed), !x); + let a = <$atomic_type>::new(y); + assert_eq!(a.fetch_not(order), y); + assert_eq!(a.load(Ordering::Relaxed), !y); + } + true + } } } };