use std::fmt;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use crate::atomic::traits::Atomic;
use crate::atomic::traits::AtomicNumber;
#[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 {
let mut current = self.load();
loop {
let new = current + delta;
match self.compare_set_weak(current, new) {
Ok(_) => return current,
Err(actual) => current = actual,
}
}
}
#[inline]
pub fn fetch_sub(&self, delta: f32) -> f32 {
let mut current = self.load();
loop {
let new = current - delta;
match self.compare_set_weak(current, new) {
Ok(_) => return current,
Err(actual) => current = actual,
}
}
}
#[inline]
pub fn fetch_mul(&self, factor: f32) -> f32 {
let mut current = self.load();
loop {
let new = current * factor;
match self.compare_set_weak(current, new) {
Ok(_) => return current,
Err(actual) => current = actual,
}
}
}
#[inline]
pub fn fetch_div(&self, divisor: f32) -> f32 {
let mut current = self.load();
loop {
let new = current / divisor;
match self.compare_set_weak(current, new) {
Ok(_) => return current,
Err(actual) => current = actual,
}
}
}
#[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 inner(&self) -> &AtomicU32 {
&self.inner
}
}
impl Atomic 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)
}
}
impl AtomicNumber 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)
}
}
impl Default for AtomicF32 {
#[inline]
fn default() -> Self {
Self::new(0.0)
}
}
impl From<f32> for AtomicF32 {
#[inline]
fn from(value: f32) -> Self {
Self::new(value)
}
}
impl fmt::Debug for AtomicF32 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AtomicF32")
.field("value", &self.load())
.finish()
}
}
impl fmt::Display for AtomicF32 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.load())
}
}