use std::fmt;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use crate::atomic::traits::Atomic;
use crate::atomic::traits::AtomicNumber;
#[repr(transparent)]
pub struct AtomicF64 {
inner: AtomicU64,
}
impl AtomicF64 {
#[inline]
pub fn new(value: f64) -> Self {
Self {
inner: AtomicU64::new(value.to_bits()),
}
}
#[inline]
pub fn load(&self) -> f64 {
f64::from_bits(self.inner.load(Ordering::Acquire))
}
#[inline]
pub fn store(&self, value: f64) {
self.inner.store(value.to_bits(), Ordering::Release);
}
#[inline]
pub fn swap(&self, value: f64) -> f64 {
f64::from_bits(self.inner.swap(value.to_bits(), Ordering::AcqRel))
}
#[inline]
pub fn compare_set(&self, current: f64, new: f64) -> Result<(), f64> {
self.inner
.compare_exchange(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
)
.map(|_| ())
.map_err(f64::from_bits)
}
#[inline]
pub fn compare_set_weak(&self, current: f64, new: f64) -> Result<(), f64> {
self.inner
.compare_exchange_weak(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
)
.map(|_| ())
.map_err(f64::from_bits)
}
#[inline]
pub fn compare_and_exchange(&self, current: f64, new: f64) -> f64 {
match self.inner.compare_exchange(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(prev_bits) => f64::from_bits(prev_bits),
Err(actual_bits) => f64::from_bits(actual_bits),
}
}
#[inline]
pub fn compare_and_exchange_weak(&self, current: f64, new: f64) -> f64 {
match self.inner.compare_exchange_weak(
current.to_bits(),
new.to_bits(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(prev_bits) => f64::from_bits(prev_bits),
Err(actual_bits) => f64::from_bits(actual_bits),
}
}
#[inline]
pub fn fetch_add(&self, delta: f64) -> f64 {
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: f64) -> f64 {
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: f64) -> f64 {
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: f64) -> f64 {
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) -> f64
where
F: Fn(f64) -> f64,
{
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) -> &AtomicU64 {
&self.inner
}
}
impl Atomic for AtomicF64 {
type Value = f64;
#[inline]
fn load(&self) -> f64 {
self.load()
}
#[inline]
fn store(&self, value: f64) {
self.store(value);
}
#[inline]
fn swap(&self, value: f64) -> f64 {
self.swap(value)
}
#[inline]
fn compare_set(&self, current: f64, new: f64) -> Result<(), f64> {
self.compare_set(current, new)
}
#[inline]
fn compare_set_weak(&self, current: f64, new: f64) -> Result<(), f64> {
self.compare_set_weak(current, new)
}
#[inline]
fn compare_exchange(&self, current: f64, new: f64) -> f64 {
self.compare_and_exchange(current, new)
}
#[inline]
fn compare_exchange_weak(&self, current: f64, new: f64) -> f64 {
self.compare_and_exchange_weak(current, new)
}
#[inline]
fn fetch_update<F>(&self, f: F) -> f64
where
F: Fn(f64) -> f64,
{
self.fetch_update(f)
}
}
impl AtomicNumber for AtomicF64 {
#[inline]
fn fetch_add(&self, delta: f64) -> f64 {
self.fetch_add(delta)
}
#[inline]
fn fetch_sub(&self, delta: f64) -> f64 {
self.fetch_sub(delta)
}
#[inline]
fn fetch_mul(&self, factor: f64) -> f64 {
self.fetch_mul(factor)
}
#[inline]
fn fetch_div(&self, divisor: f64) -> f64 {
self.fetch_div(divisor)
}
}
unsafe impl Send for AtomicF64 {}
unsafe impl Sync for AtomicF64 {}
impl Default for AtomicF64 {
#[inline]
fn default() -> Self {
Self::new(0.0)
}
}
impl From<f64> for AtomicF64 {
#[inline]
fn from(value: f64) -> Self {
Self::new(value)
}
}
impl fmt::Debug for AtomicF64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AtomicF64")
.field("value", &self.load())
.finish()
}
}
impl fmt::Display for AtomicF64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.load())
}
}