Skip to content

Commit

Permalink
Add AtomicCell::fetch_update
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed May 28, 2021
1 parent 0e7d89a commit 9e5ac90
Showing 1 changed file with 34 additions and 0 deletions.
34 changes: 34 additions & 0 deletions crossbeam-utils/src/atomic/atomic_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,40 @@ impl<T: Copy + Eq> AtomicCell<T> {
pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> {
unsafe { atomic_compare_exchange_weak(self.value.get(), current, new) }
}

/// 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.
///
/// # Examples
///
/// ```rust
/// use crossbeam_utils::atomic::AtomicCell;
///
/// let a = AtomicCell::new(7);
/// assert_eq!(a.fetch_update(|_| None), Err(7));
/// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(7));
/// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(8));
/// assert_eq!(a.load(), 9);
/// ```
#[inline]
pub fn fetch_update<F>(&self, mut f: F) -> Result<T, T>
where
F: FnMut(T) -> Option<T>,
{
let mut prev = self.load();
while let Some(next) = f(prev) {
match self.compare_exchange(prev, next) {
x @ Ok(_) => return x,
Err(next_prev) => prev = next_prev,
}
}
Err(prev)
}
}

macro_rules! impl_arithmetic {
Expand Down

0 comments on commit 9e5ac90

Please sign in to comment.