use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use crate::atomic::atomic_number_ops::AtomicNumberOps;
use crate::atomic::atomic_ops::AtomicOps;
#[repr(transparent)]
pub struct AtomicF32 {
inner: AtomicU32,
}
impl AtomicF32 {
#[inline]
pub fn new(value: f32) -> Self {
Self {
inner: AtomicU32::new(value.to_bits()),
}
}
#[inline]
pub fn load(&self) -> f32 {
f32::from_bits(self.inner.load(Ordering::Acquire))
}
#[inline]
pub fn store(&self, value: f32) {
self.inner.store(value.to_bits(), Ordering::Release);
}
#[inline]
pub fn swap(&self, value: f32) -> f32 {
f32::from_bits(self.inner.swap(value.to_bits(), Ordering::AcqRel))
}
#[inline]
pub fn compare_set(&self, current: f32, new: f32) -> Result<(), f32> {
self.inner
.compare_exchange(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
)
.map(|_| ())
.map_err(f32::from_bits)
}
#[inline]
pub fn compare_set_weak(&self, current: f32, new: f32) -> Result<(), f32> {
self.inner
.compare_exchange_weak(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
)
.map(|_| ())
.map_err(f32::from_bits)
}
#[inline]
pub fn compare_and_exchange(&self, current: f32, new: f32) -> f32 {
match self.inner.compare_exchange(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(prev_bits) => f32::from_bits(prev_bits),
Err(actual_bits) => f32::from_bits(actual_bits),
}
}
#[inline]
pub fn compare_and_exchange_weak(&self, current: f32, new: f32) -> f32 {
match self.inner.compare_exchange_weak(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(prev_bits) => f32::from_bits(prev_bits),
Err(actual_bits) => f32::from_bits(actual_bits),
}
}
#[inline]
pub fn fetch_add(&self, delta: f32) -> f32 {
self.fetch_update(|current| current + delta)
}
#[inline]
pub fn fetch_sub(&self, delta: f32) -> f32 {
self.fetch_update(|current| current - delta)
}
#[inline]
pub fn fetch_mul(&self, factor: f32) -> f32 {
self.fetch_update(|current| current * factor)
}
#[inline]
pub fn fetch_div(&self, divisor: f32) -> f32 {
self.fetch_update(|current| current / divisor)
}
#[inline]
pub fn fetch_update<F>(&self, f: F) -> f32
where
F: Fn(f32) -> f32,
{
let mut current = self.load();
loop {
let new = f(current);
match self.compare_set_weak(current, new) {
Ok(_) => return current,
Err(actual) => current = actual,
}
}
}
#[inline]
pub fn try_update<F>(&self, f: F) -> Option<f32>
where
F: Fn(f32) -> Option<f32>,
{
let mut current = self.load();
loop {
let new = f(current)?;
match self.compare_set_weak(current, new) {
Ok(_) => return Some(current),
Err(actual) => current = actual,
}
}
}
#[inline]
pub fn inner(&self) -> &AtomicU32 {
&self.inner
}
}
impl AtomicOps for AtomicF32 {
type Value = f32;
#[inline]
fn load(&self) -> f32 {
self.load()
}
#[inline]
fn store(&self, value: f32) {
self.store(value);
}
#[inline]
fn swap(&self, value: f32) -> f32 {
self.swap(value)
}
#[inline]
fn compare_set(&self, current: f32, new: f32) -> Result<(), f32> {
self.compare_set(current, new)
}
#[inline]
fn compare_set_weak(&self, current: f32, new: f32) -> Result<(), f32> {
self.compare_set_weak(current, new)
}
#[inline]
fn compare_exchange(&self, current: f32, new: f32) -> f32 {
self.compare_and_exchange(current, new)
}
#[inline]
fn compare_exchange_weak(&self, current: f32, new: f32) -> f32 {
self.compare_and_exchange_weak(current, new)
}
#[inline]
fn fetch_update<F>(&self, f: F) -> f32
where
F: Fn(f32) -> f32,
{
self.fetch_update(f)
}
#[inline]
fn try_update<F>(&self, f: F) -> Option<f32>
where
F: Fn(f32) -> Option<f32>,
{
self.try_update(f)
}
}
impl AtomicNumberOps for AtomicF32 {
#[inline]
fn fetch_add(&self, delta: f32) -> f32 {
self.fetch_add(delta)
}
#[inline]
fn fetch_sub(&self, delta: f32) -> f32 {
self.fetch_sub(delta)
}
#[inline]
fn fetch_mul(&self, factor: f32) -> f32 {
self.fetch_mul(factor)
}
#[inline]
fn fetch_div(&self, divisor: f32) -> f32 {
self.fetch_div(divisor)
}
}