Skip to content

Commit 9e5ac90

Browse files
committed
Add AtomicCell::fetch_update
1 parent 0e7d89a commit 9e5ac90

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

crossbeam-utils/src/atomic/atomic_cell.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,40 @@ impl<T: Copy + Eq> AtomicCell<T> {
258258
pub fn compare_exchange(&self, current: T, new: T) -> Result<T, T> {
259259
unsafe { atomic_compare_exchange_weak(self.value.get(), current, new) }
260260
}
261+
262+
/// Fetches the value, and applies a function to it that returns an optional
263+
/// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
264+
/// `Err(previous_value)`.
265+
///
266+
/// Note: This may call the function multiple times if the value has been changed from other threads in
267+
/// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
268+
/// only once to the stored value.
269+
///
270+
/// # Examples
271+
///
272+
/// ```rust
273+
/// use crossbeam_utils::atomic::AtomicCell;
274+
///
275+
/// let a = AtomicCell::new(7);
276+
/// assert_eq!(a.fetch_update(|_| None), Err(7));
277+
/// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(7));
278+
/// assert_eq!(a.fetch_update(|a| Some(a + 1)), Ok(8));
279+
/// assert_eq!(a.load(), 9);
280+
/// ```
281+
#[inline]
282+
pub fn fetch_update<F>(&self, mut f: F) -> Result<T, T>
283+
where
284+
F: FnMut(T) -> Option<T>,
285+
{
286+
let mut prev = self.load();
287+
while let Some(next) = f(prev) {
288+
match self.compare_exchange(prev, next) {
289+
x @ Ok(_) => return x,
290+
Err(next_prev) => prev = next_prev,
291+
}
292+
}
293+
Err(prev)
294+
}
261295
}
262296

263297
macro_rules! impl_arithmetic {

0 commit comments

Comments
 (0)