Skip to content

Commit 50ba3af

Browse files
committed
Add AtomicCell::{fetch_nand,fetch_max,fetch_min}
1 parent 5f5dbb9 commit 50ba3af

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

crossbeam-utils/src/atomic/atomic_cell.rs

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use crate::primitive::sync::atomic::{self, AtomicBool};
55
use core::cell::UnsafeCell;
6+
use core::cmp;
67
use core::fmt;
78
use core::mem;
89
use core::sync::atomic::Ordering;
@@ -387,6 +388,35 @@ macro_rules! impl_arithmetic {
387388
}
388389
}
389390

391+
/// Applies bitwise "nand" to the current value and returns the previous value.
392+
///
393+
/// # Examples
394+
///
395+
/// ```
396+
/// use crossbeam_utils::atomic::AtomicCell;
397+
///
398+
#[doc = $example]
399+
///
400+
/// assert_eq!(a.fetch_nand(3), 7);
401+
/// assert_eq!(a.load(), !(7 & 3));
402+
/// ```
403+
#[inline]
404+
pub fn fetch_nand(&self, val: $t) -> $t {
405+
#[cfg(crossbeam_loom)]
406+
{
407+
let _ = val;
408+
unimplemented!("loom does not support non-atomic atomic ops");
409+
}
410+
#[cfg(not(crossbeam_loom))]
411+
{
412+
let _guard = lock(self.value.get() as usize).write();
413+
let value = unsafe { &mut *(self.value.get()) };
414+
let old = *value;
415+
*value = !(old & val);
416+
old
417+
}
418+
}
419+
390420
/// Applies bitwise "or" to the current value and returns the previous value.
391421
///
392422
/// # Examples
@@ -444,6 +474,66 @@ macro_rules! impl_arithmetic {
444474
old
445475
}
446476
}
477+
478+
/// Compares and sets the maximum of the current value and `val`,
479+
/// and returns the previous value.
480+
///
481+
/// # Examples
482+
///
483+
/// ```
484+
/// use crossbeam_utils::atomic::AtomicCell;
485+
///
486+
#[doc = $example]
487+
///
488+
/// assert_eq!(a.fetch_max(2), 7);
489+
/// assert_eq!(a.load(), 7);
490+
/// ```
491+
#[inline]
492+
pub fn fetch_max(&self, val: $t) -> $t {
493+
#[cfg(crossbeam_loom)]
494+
{
495+
let _ = val;
496+
unimplemented!("loom does not support non-atomic atomic ops");
497+
}
498+
#[cfg(not(crossbeam_loom))]
499+
{
500+
let _guard = lock(self.value.get() as usize).write();
501+
let value = unsafe { &mut *(self.value.get()) };
502+
let old = *value;
503+
*value = cmp::max(old, val);
504+
old
505+
}
506+
}
507+
508+
/// Compares and sets the minimum of the current value and `val`,
509+
/// and returns the previous value.
510+
///
511+
/// # Examples
512+
///
513+
/// ```
514+
/// use crossbeam_utils::atomic::AtomicCell;
515+
///
516+
#[doc = $example]
517+
///
518+
/// assert_eq!(a.fetch_min(2), 7);
519+
/// assert_eq!(a.load(), 2);
520+
/// ```
521+
#[inline]
522+
pub fn fetch_min(&self, val: $t) -> $t {
523+
#[cfg(crossbeam_loom)]
524+
{
525+
let _ = val;
526+
unimplemented!("loom does not support non-atomic atomic ops");
527+
}
528+
#[cfg(not(crossbeam_loom))]
529+
{
530+
let _guard = lock(self.value.get() as usize).write();
531+
let value = unsafe { &mut *(self.value.get()) };
532+
let old = *value;
533+
*value = cmp::min(old, val);
534+
old
535+
}
536+
}
447537
}
448538
};
449539
($t:ty, $atomic:ty, $example:tt) => {
@@ -554,6 +644,40 @@ macro_rules! impl_arithmetic {
554644
}
555645
}
556646

647+
/// Applies bitwise "nand" to the current value and returns the previous value.
648+
///
649+
/// # Examples
650+
///
651+
/// ```
652+
/// use crossbeam_utils::atomic::AtomicCell;
653+
///
654+
#[doc = $example]
655+
///
656+
/// assert_eq!(a.fetch_nand(3), 7);
657+
/// assert_eq!(a.load(), !(7 & 3));
658+
/// ```
659+
#[inline]
660+
pub fn fetch_nand(&self, val: $t) -> $t {
661+
if can_transmute::<$t, $atomic>() {
662+
let a = unsafe { &*(self.value.get() as *const $atomic) };
663+
a.fetch_nand(val, Ordering::AcqRel)
664+
} else {
665+
#[cfg(crossbeam_loom)]
666+
{
667+
let _ = val;
668+
unimplemented!("loom does not support non-atomic atomic ops");
669+
}
670+
#[cfg(not(crossbeam_loom))]
671+
{
672+
let _guard = lock(self.value.get() as usize).write();
673+
let value = unsafe { &mut *(self.value.get()) };
674+
let old = *value;
675+
*value = !(old & val);
676+
old
677+
}
678+
}
679+
}
680+
557681
/// Applies bitwise "or" to the current value and returns the previous value.
558682
///
559683
/// # Examples
@@ -621,6 +745,76 @@ macro_rules! impl_arithmetic {
621745
}
622746
}
623747
}
748+
749+
/// Compares and sets the maximum of the current value and `val`,
750+
/// and returns the previous value.
751+
///
752+
/// # Examples
753+
///
754+
/// ```
755+
/// use crossbeam_utils::atomic::AtomicCell;
756+
///
757+
#[doc = $example]
758+
///
759+
/// assert_eq!(a.fetch_max(9), 7);
760+
/// assert_eq!(a.load(), 9);
761+
/// ```
762+
#[inline]
763+
pub fn fetch_max(&self, val: $t) -> $t {
764+
if can_transmute::<$t, $atomic>() {
765+
// TODO: Atomic*::fetch_max requires Rust 1.45.
766+
self.fetch_update(|old| Some(cmp::max(old, val))).unwrap()
767+
} else {
768+
#[cfg(crossbeam_loom)]
769+
{
770+
let _ = val;
771+
unimplemented!("loom does not support non-atomic atomic ops");
772+
}
773+
#[cfg(not(crossbeam_loom))]
774+
{
775+
let _guard = lock(self.value.get() as usize).write();
776+
let value = unsafe { &mut *(self.value.get()) };
777+
let old = *value;
778+
*value = cmp::max(old, val);
779+
old
780+
}
781+
}
782+
}
783+
784+
/// Compares and sets the minimum of the current value and `val`,
785+
/// and returns the previous value.
786+
///
787+
/// # Examples
788+
///
789+
/// ```
790+
/// use crossbeam_utils::atomic::AtomicCell;
791+
///
792+
#[doc = $example]
793+
///
794+
/// assert_eq!(a.fetch_min(2), 7);
795+
/// assert_eq!(a.load(), 2);
796+
/// ```
797+
#[inline]
798+
pub fn fetch_min(&self, val: $t) -> $t {
799+
if can_transmute::<$t, $atomic>() {
800+
// TODO: Atomic*::fetch_min requires Rust 1.45.
801+
self.fetch_update(|old| Some(cmp::min(old, val))).unwrap()
802+
} else {
803+
#[cfg(crossbeam_loom)]
804+
{
805+
let _ = val;
806+
unimplemented!("loom does not support non-atomic atomic ops");
807+
}
808+
#[cfg(not(crossbeam_loom))]
809+
{
810+
let _guard = lock(self.value.get() as usize).write();
811+
let value = unsafe { &mut *(self.value.get()) };
812+
let old = *value;
813+
*value = cmp::min(old, val);
814+
old
815+
}
816+
}
817+
}
624818
}
625819
};
626820
}
@@ -678,6 +872,30 @@ impl AtomicCell<bool> {
678872
a.fetch_and(val, Ordering::AcqRel)
679873
}
680874

875+
/// Applies logical "nand" to the current value and returns the previous value.
876+
///
877+
/// # Examples
878+
///
879+
/// ```
880+
/// use crossbeam_utils::atomic::AtomicCell;
881+
///
882+
/// let a = AtomicCell::new(true);
883+
///
884+
/// assert_eq!(a.fetch_nand(false), true);
885+
/// assert_eq!(a.load(), true);
886+
///
887+
/// assert_eq!(a.fetch_nand(true), true);
888+
/// assert_eq!(a.load(), false);
889+
///
890+
/// assert_eq!(a.fetch_nand(false), false);
891+
/// assert_eq!(a.load(), true);
892+
/// ```
893+
#[inline]
894+
pub fn fetch_nand(&self, val: bool) -> bool {
895+
let a = unsafe { &*(self.value.get() as *const AtomicBool) };
896+
a.fetch_nand(val, Ordering::AcqRel)
897+
}
898+
681899
/// Applies logical "or" to the current value and returns the previous value.
682900
///
683901
/// # Examples

crossbeam-utils/tests/atomic_cell.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,15 @@ macro_rules! test_arithmetic {
286286

287287
assert_eq!(a.fetch_xor(2), 19);
288288
assert_eq!(a.load(), 17);
289+
290+
assert_eq!(a.fetch_max(18), 17);
291+
assert_eq!(a.load(), 18);
292+
293+
assert_eq!(a.fetch_min(17), 18);
294+
assert_eq!(a.load(), 17);
295+
296+
assert_eq!(a.fetch_nand(7), 17);
297+
assert_eq!(a.load(), !(17 & 7));
289298
}
290299
};
291300
}

0 commit comments

Comments
 (0)