Make Fixed, GuardedFixed thread-safe
This commit is contained in:
parent
e1e347c255
commit
f12db205b9
|
@ -20,21 +20,27 @@ use super::{Assign, Number};
|
|||
use ibig::{IBig, ops::Abs};
|
||||
use num_traits::{Num, One, Signed, Zero};
|
||||
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::cmp::{Ord, PartialEq, PartialOrd};
|
||||
use std::ops;
|
||||
use std::fmt;
|
||||
|
||||
static mut DPS: Option<usize> = None;
|
||||
static mut FACTOR: Option<IBig> = None;
|
||||
|
||||
#[inline]
|
||||
pub fn get_dps() -> usize {
|
||||
unsafe { DPS.expect("Attempted Fixed arithmetic before dps set") }
|
||||
thread_local! {
|
||||
static DPS: Cell<usize> = Cell::new(5);
|
||||
static FACTOR: UnsafeCell<IBig> = UnsafeCell::new(IBig::from(10).pow(5));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_factor() -> &'static IBig {
|
||||
unsafe { FACTOR.as_ref().expect("Attempted Fixed arithmetic before dps set") }
|
||||
pub fn get_dps() -> usize {
|
||||
return DPS.with(|dps_cell| dps_cell.get());
|
||||
}
|
||||
|
||||
fn get_factor<'a>() -> &'a IBig {
|
||||
FACTOR.with(|factor_cell| {
|
||||
let factor_ptr = factor_cell.get();
|
||||
// SAFETY: Safe if requirements of Fixed::set_dps met
|
||||
let factor_ref = unsafe { &*factor_ptr };
|
||||
return factor_ref;
|
||||
})
|
||||
}
|
||||
|
||||
/// Fixed-point number
|
||||
|
@ -43,11 +49,20 @@ pub struct Fixed(IBig);
|
|||
|
||||
impl Fixed {
|
||||
/// Set the number of decimal places to compute results to
|
||||
///
|
||||
/// SAFETY: This must be called before, and never after, any operations on [Fixed].
|
||||
pub fn set_dps(dps: usize) {
|
||||
DPS.with(|dps_cell| {
|
||||
dps_cell.set(dps);
|
||||
});
|
||||
FACTOR.with(|factor_cell| {
|
||||
let factor = IBig::from(10).pow(dps);
|
||||
let factor_ptr = factor_cell.get();
|
||||
// SAFETY: Safe if requirements above met
|
||||
unsafe {
|
||||
DPS = Some(dps);
|
||||
FACTOR = Some(IBig::from(10).pow(dps));
|
||||
*factor_ptr = factor;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,22 +140,22 @@ impl Number for Fixed {
|
|||
|
||||
#[test]
|
||||
fn rounding() {
|
||||
Fixed::set_dps(2);
|
||||
Fixed::set_dps(5);
|
||||
|
||||
let mut x = Fixed::parse("555.50"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.52"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.55"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.57"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("55.550"); x.floor_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.552"); x.floor_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.555"); x.floor_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.557"); x.floor_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
|
||||
let mut x = Fixed::parse("555.50"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.52"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
|
||||
let mut x = Fixed::parse("555.55"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
|
||||
let mut x = Fixed::parse("555.57"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
|
||||
let mut x = Fixed::parse("55.550"); x.ceil_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.552"); x.ceil_mut(2); assert_eq!(x, Fixed::parse("55.56"));
|
||||
let mut x = Fixed::parse("55.555"); x.ceil_mut(2); assert_eq!(x, Fixed::parse("55.56"));
|
||||
let mut x = Fixed::parse("55.557"); x.ceil_mut(2); assert_eq!(x, Fixed::parse("55.56"));
|
||||
|
||||
let mut x = Fixed::parse("555.50"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.52"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.5"));
|
||||
let mut x = Fixed::parse("555.55"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.6"));
|
||||
let mut x = Fixed::parse("555.57"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.6"));
|
||||
let mut x = Fixed::parse("55.550"); x.round_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.552"); x.round_mut(2); assert_eq!(x, Fixed::parse("55.55"));
|
||||
let mut x = Fixed::parse("55.555"); x.round_mut(2); assert_eq!(x, Fixed::parse("55.56"));
|
||||
let mut x = Fixed::parse("55.557"); x.round_mut(2); assert_eq!(x, Fixed::parse("55.56"));
|
||||
}
|
||||
|
||||
impl Num for Fixed {
|
||||
|
|
|
@ -20,27 +20,37 @@ use super::{Assign, Number};
|
|||
use ibig::{IBig, ops::Abs};
|
||||
use num_traits::{Num, One, Signed, Zero};
|
||||
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::ops;
|
||||
use std::fmt;
|
||||
|
||||
static mut DPS: Option<usize> = None;
|
||||
static mut FACTOR: Option<IBig> = None;
|
||||
static mut FACTOR_CMP: Option<IBig> = None;
|
||||
thread_local! {
|
||||
static DPS: Cell<usize> = Cell::new(5);
|
||||
static FACTOR: UnsafeCell<IBig> = UnsafeCell::new(IBig::from(10).pow(10));
|
||||
static FACTOR_CMP: UnsafeCell<IBig> = UnsafeCell::new(IBig::from(10).pow(5) / IBig::from(2));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_dps() -> usize {
|
||||
unsafe { DPS.expect("Attempted GuardedFixed arithmetic before dps set") }
|
||||
return DPS.with(|dps_cell| dps_cell.get());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_factor() -> &'static IBig {
|
||||
unsafe { FACTOR.as_ref().expect("Attempted GuardedFixed arithmetic before dps set") }
|
||||
fn get_factor<'a>() -> &'a IBig {
|
||||
FACTOR.with(|factor_cell| {
|
||||
let factor_ptr = factor_cell.get();
|
||||
// SAFETY: Safe if requirements of GuardedFixed::set_dps met
|
||||
let factor_ref = unsafe { &*factor_ptr };
|
||||
return factor_ref;
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_factor_cmp() -> &'static IBig {
|
||||
unsafe { FACTOR_CMP.as_ref().expect("Attempted GuardedFixed arithmetic before dps set") }
|
||||
fn get_factor_cmp<'a>() -> &'a IBig {
|
||||
FACTOR_CMP.with(|factor_cmp_cell| {
|
||||
let factor_cmp_ptr = factor_cmp_cell.get();
|
||||
// SAFETY: Safe if requirements of Fixed::set_dps met
|
||||
let factor_cmp_ref = unsafe { &*factor_cmp_ptr };
|
||||
return factor_cmp_ref;
|
||||
})
|
||||
}
|
||||
|
||||
/// Guarded fixed-point number
|
||||
|
@ -49,12 +59,28 @@ pub struct GuardedFixed(IBig);
|
|||
|
||||
impl GuardedFixed {
|
||||
/// Set the number of decimal places to compute results to
|
||||
///
|
||||
/// SAFETY: This must be called before, and never after, any operations on [GuardedFixed].
|
||||
pub fn set_dps(dps: usize) {
|
||||
DPS.with(|dps_cell| {
|
||||
dps_cell.set(dps);
|
||||
});
|
||||
FACTOR.with(|factor_cell| {
|
||||
let factor = IBig::from(10).pow(dps * 2);
|
||||
let factor_ptr = factor_cell.get();
|
||||
// SAFETY: Safe if requirements above met
|
||||
unsafe {
|
||||
DPS = Some(dps);
|
||||
FACTOR = Some(IBig::from(10).pow(dps * 2));
|
||||
FACTOR_CMP = Some(IBig::from(10).pow(dps) / IBig::from(2));
|
||||
*factor_ptr = factor;
|
||||
}
|
||||
});
|
||||
FACTOR_CMP.with(|factor_cmp_cell| {
|
||||
let factor_cmp = IBig::from(10).pow(dps) / IBig::from(2);
|
||||
let factor_cmp_ptr = factor_cmp_cell.get();
|
||||
// SAFETY: Safe if requirements above met
|
||||
unsafe {
|
||||
*factor_cmp_ptr = factor_cmp;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,22 +158,22 @@ impl Number for GuardedFixed {
|
|||
|
||||
#[test]
|
||||
fn rounding() {
|
||||
GuardedFixed::set_dps(2);
|
||||
GuardedFixed::set_dps(5);
|
||||
|
||||
let mut x = GuardedFixed::parse("555.50"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.52"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.55"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.57"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("55.550"); x.floor_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.552"); x.floor_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.555"); x.floor_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.557"); x.floor_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
|
||||
let mut x = GuardedFixed::parse("555.50"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.52"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
|
||||
let mut x = GuardedFixed::parse("555.55"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
|
||||
let mut x = GuardedFixed::parse("555.57"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
|
||||
let mut x = GuardedFixed::parse("55.550"); x.ceil_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.552"); x.ceil_mut(2); assert_eq!(x, GuardedFixed::parse("55.56"));
|
||||
let mut x = GuardedFixed::parse("55.555"); x.ceil_mut(2); assert_eq!(x, GuardedFixed::parse("55.56"));
|
||||
let mut x = GuardedFixed::parse("55.557"); x.ceil_mut(2); assert_eq!(x, GuardedFixed::parse("55.56"));
|
||||
|
||||
let mut x = GuardedFixed::parse("555.50"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.52"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
|
||||
let mut x = GuardedFixed::parse("555.55"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
|
||||
let mut x = GuardedFixed::parse("555.57"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
|
||||
let mut x = GuardedFixed::parse("55.550"); x.round_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.552"); x.round_mut(2); assert_eq!(x, GuardedFixed::parse("55.55"));
|
||||
let mut x = GuardedFixed::parse("55.555"); x.round_mut(2); assert_eq!(x, GuardedFixed::parse("55.56"));
|
||||
let mut x = GuardedFixed::parse("55.557"); x.round_mut(2); assert_eq!(x, GuardedFixed::parse("55.56"));
|
||||
}
|
||||
|
||||
impl Num for GuardedFixed {
|
||||
|
|
Loading…
Reference in New Issue