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