Add fetch_update methods to AtomicBool and AtomicPtr
These methods were stabilized for the integer atomics in #71843, but the methods were not added for the non-integer atomics `AtomicBool` and `AtomicPtr`.
This commit is contained in:
parent
1899c489d4
commit
00f32e6631
@ -801,6 +801,64 @@ impl AtomicBool {
|
||||
pub fn as_mut_ptr(&self) -> *mut bool {
|
||||
self.v.get() as *mut bool
|
||||
}
|
||||
|
||||
/// Fetches the value, and applies a function to it that returns an optional
|
||||
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
|
||||
/// returned `Some(_)`, else `Err(previous_value)`.
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been
|
||||
/// changed from other threads in the meantime, as long as the function
|
||||
/// returns `Some(_)`, but the function will have been applied only once to
|
||||
/// the stored value.
|
||||
///
|
||||
/// `fetch_update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicBool::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part of this
|
||||
/// operation [`Relaxed`], and using [`Release`] makes the final successful
|
||||
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
|
||||
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
|
||||
/// success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_fetch_update)]
|
||||
/// use std::sync::atomic::{AtomicBool, Ordering};
|
||||
///
|
||||
/// let x = AtomicBool::new(false);
|
||||
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false));
|
||||
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false));
|
||||
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true));
|
||||
/// assert_eq!(x.load(Ordering::SeqCst), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")]
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
pub fn fetch_update<F>(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
mut f: F,
|
||||
) -> Result<bool, bool>
|
||||
where
|
||||
F: FnMut(bool) -> Option<bool>,
|
||||
{
|
||||
let mut prev = self.load(fetch_order);
|
||||
while let Some(next) = f(prev) {
|
||||
match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
|
||||
x @ Ok(_) => return x,
|
||||
Err(next_prev) => prev = next_prev,
|
||||
}
|
||||
}
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic_load_store = "ptr")]
|
||||
@ -1123,6 +1181,73 @@ impl<T> AtomicPtr<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches the value, and applies a function to it that returns an optional
|
||||
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
|
||||
/// returned `Some(_)`, else `Err(previous_value)`.
|
||||
///
|
||||
/// Note: This may call the function multiple times if the value has been
|
||||
/// changed from other threads in the meantime, as long as the function
|
||||
/// returns `Some(_)`, but the function will have been applied only once to
|
||||
/// the stored value.
|
||||
///
|
||||
/// `fetch_update` takes two [`Ordering`] arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering for
|
||||
/// when the operation finally succeeds while the second describes the
|
||||
/// required ordering for loads. These correspond to the success and failure
|
||||
/// orderings of [`AtomicPtr::compare_exchange`] respectively.
|
||||
///
|
||||
/// Using [`Acquire`] as success ordering makes the store part of this
|
||||
/// operation [`Relaxed`], and using [`Release`] makes the final successful
|
||||
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
|
||||
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
|
||||
/// success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(atomic_fetch_update)]
|
||||
/// use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
///
|
||||
/// let ptr: *mut _ = &mut 5;
|
||||
/// let some_ptr = AtomicPtr::new(ptr);
|
||||
///
|
||||
/// let new: *mut _ = &mut 10;
|
||||
/// assert_eq!(some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr));
|
||||
/// let result = some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||
/// if x == ptr {
|
||||
/// Some(new)
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// });
|
||||
/// assert_eq!(result, Ok(ptr));
|
||||
/// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")]
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
pub fn fetch_update<F>(
|
||||
&self,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
mut f: F,
|
||||
) -> Result<*mut T, *mut T>
|
||||
where
|
||||
F: FnMut(*mut T) -> Option<*mut T>,
|
||||
{
|
||||
let mut prev = self.load(fetch_order);
|
||||
while let Some(next) = f(prev) {
|
||||
match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
|
||||
x @ Ok(_) => return x,
|
||||
Err(next_prev) => prev = next_prev,
|
||||
}
|
||||
}
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic_load_store = "8")]
|
||||
|
Loading…
Reference in New Issue
Block a user