Skip to content

Commit

Permalink
Merge #785
Browse files Browse the repository at this point in the history
785: Add AtomicCell::{fetch_nand,fetch_max,fetch_min} r=taiki-e a=taiki-e

refs:

- [AtomicUsize::fetch_nand](https://doc.rust-lang.org/core/sync/atomic/struct.AtomicUsize.html#method.fetch_nand)
- [AtomicUsize::fetch_max](https://doc.rust-lang.org/core/sync/atomic/struct.AtomicUsize.html#method.fetch_max)
- [AtomicUsize::fetch_min](https://doc.rust-lang.org/core/sync/atomic/struct.AtomicUsize.html#method.fetch_min)

Co-authored-by: Taiki Endo <[email protected]>
  • Loading branch information
bors[bot] and taiki-e authored Feb 5, 2022
2 parents 5f5dbb9 + 50ba3af commit bf53bd6
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 0 deletions.
218 changes: 218 additions & 0 deletions crossbeam-utils/src/atomic/atomic_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::primitive::sync::atomic::{self, AtomicBool};
use core::cell::UnsafeCell;
use core::cmp;
use core::fmt;
use core::mem;
use core::sync::atomic::Ordering;
Expand Down Expand Up @@ -387,6 +388,35 @@ macro_rules! impl_arithmetic {
}
}

/// Applies bitwise "nand" to the current value and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_nand(3), 7);
/// assert_eq!(a.load(), !(7 & 3));
/// ```
#[inline]
pub fn fetch_nand(&self, val: $t) -> $t {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = !(old & val);
old
}
}

/// Applies bitwise "or" to the current value and returns the previous value.
///
/// # Examples
Expand Down Expand Up @@ -444,6 +474,66 @@ macro_rules! impl_arithmetic {
old
}
}

/// Compares and sets the maximum of the current value and `val`,
/// and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_max(2), 7);
/// assert_eq!(a.load(), 7);
/// ```
#[inline]
pub fn fetch_max(&self, val: $t) -> $t {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = cmp::max(old, val);
old
}
}

/// Compares and sets the minimum of the current value and `val`,
/// and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_min(2), 7);
/// assert_eq!(a.load(), 2);
/// ```
#[inline]
pub fn fetch_min(&self, val: $t) -> $t {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = cmp::min(old, val);
old
}
}
}
};
($t:ty, $atomic:ty, $example:tt) => {
Expand Down Expand Up @@ -554,6 +644,40 @@ macro_rules! impl_arithmetic {
}
}

/// Applies bitwise "nand" to the current value and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_nand(3), 7);
/// assert_eq!(a.load(), !(7 & 3));
/// ```
#[inline]
pub fn fetch_nand(&self, val: $t) -> $t {
if can_transmute::<$t, $atomic>() {
let a = unsafe { &*(self.value.get() as *const $atomic) };
a.fetch_nand(val, Ordering::AcqRel)
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = !(old & val);
old
}
}
}

/// Applies bitwise "or" to the current value and returns the previous value.
///
/// # Examples
Expand Down Expand Up @@ -621,6 +745,76 @@ macro_rules! impl_arithmetic {
}
}
}

/// Compares and sets the maximum of the current value and `val`,
/// and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_max(9), 7);
/// assert_eq!(a.load(), 9);
/// ```
#[inline]
pub fn fetch_max(&self, val: $t) -> $t {
if can_transmute::<$t, $atomic>() {
// TODO: Atomic*::fetch_max requires Rust 1.45.
self.fetch_update(|old| Some(cmp::max(old, val))).unwrap()
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = cmp::max(old, val);
old
}
}
}

/// Compares and sets the minimum of the current value and `val`,
/// and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
#[doc = $example]
///
/// assert_eq!(a.fetch_min(2), 7);
/// assert_eq!(a.load(), 2);
/// ```
#[inline]
pub fn fetch_min(&self, val: $t) -> $t {
if can_transmute::<$t, $atomic>() {
// TODO: Atomic*::fetch_min requires Rust 1.45.
self.fetch_update(|old| Some(cmp::min(old, val))).unwrap()
} else {
#[cfg(crossbeam_loom)]
{
let _ = val;
unimplemented!("loom does not support non-atomic atomic ops");
}
#[cfg(not(crossbeam_loom))]
{
let _guard = lock(self.value.get() as usize).write();
let value = unsafe { &mut *(self.value.get()) };
let old = *value;
*value = cmp::min(old, val);
old
}
}
}
}
};
}
Expand Down Expand Up @@ -678,6 +872,30 @@ impl AtomicCell<bool> {
a.fetch_and(val, Ordering::AcqRel)
}

/// Applies logical "nand" to the current value and returns the previous value.
///
/// # Examples
///
/// ```
/// use crossbeam_utils::atomic::AtomicCell;
///
/// let a = AtomicCell::new(true);
///
/// assert_eq!(a.fetch_nand(false), true);
/// assert_eq!(a.load(), true);
///
/// assert_eq!(a.fetch_nand(true), true);
/// assert_eq!(a.load(), false);
///
/// assert_eq!(a.fetch_nand(false), false);
/// assert_eq!(a.load(), true);
/// ```
#[inline]
pub fn fetch_nand(&self, val: bool) -> bool {
let a = unsafe { &*(self.value.get() as *const AtomicBool) };
a.fetch_nand(val, Ordering::AcqRel)
}

/// Applies logical "or" to the current value and returns the previous value.
///
/// # Examples
Expand Down
9 changes: 9 additions & 0 deletions crossbeam-utils/tests/atomic_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ macro_rules! test_arithmetic {

assert_eq!(a.fetch_xor(2), 19);
assert_eq!(a.load(), 17);

assert_eq!(a.fetch_max(18), 17);
assert_eq!(a.load(), 18);

assert_eq!(a.fetch_min(17), 18);
assert_eq!(a.load(), 17);

assert_eq!(a.fetch_nand(7), 17);
assert_eq!(a.load(), !(17 & 7));
}
};
}
Expand Down

0 comments on commit bf53bd6

Please sign in to comment.