use crate::backend::NiBackend;
use crate::compute;
use std::collections::BTreeMap;
use std::sync::RwLock;
pub struct NiCache<B: NiBackend> {
map: RwLock<BTreeMap<u32, B::Float>>,
}
impl<B: NiBackend> NiCache<B> {
pub const fn new() -> Self {
NiCache {
map: RwLock::new(BTreeMap::new()),
}
}
pub fn get_or_compute(&self, precision_bits: u32) -> B::Float {
let key = round_up(precision_bits, 64);
{
let map = self.map.read().expect("NiCache RwLock poisoned");
if let Some(cached) = map.get(&key) {
return cached.clone();
}
}
let value = compute::compute::<B>(key);
{
let mut map = self.map.write().expect("NiCache RwLock poisoned");
map.entry(key).or_insert_with(|| value.clone());
}
value
}
pub fn clear(&self) {
let mut map = self.map.write().expect("NiCache RwLock poisoned");
map.clear();
}
}
#[inline]
fn round_up(n: u32, step: u32) -> u32 {
((n + step - 1) / step) * step
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::NiFloat;
#[test]
fn round_up_works() {
assert_eq!(round_up(1, 64), 64);
assert_eq!(round_up(64, 64), 64);
assert_eq!(round_up(65, 64), 128);
assert_eq!(round_up(128, 64), 128);
}
#[cfg(feature = "backend-dashu")]
#[test]
fn cache_returns_same_value_twice() {
use crate::backend::dashu::DashuBackend;
let cache: NiCache<DashuBackend> = NiCache::new();
let a = cache.get_or_compute(128).to_f64();
let b = cache.get_or_compute(128).to_f64();
assert_eq!(a, b);
}
#[cfg(feature = "backend-dashu")]
#[test]
fn cache_clears_correctly() {
use crate::backend::NiFloat;
use crate::backend::dashu::DashuBackend;
let cache: NiCache<DashuBackend> = NiCache::new();
let _ = cache.get_or_compute(128);
cache.clear();
let val = cache.get_or_compute(128).to_f64();
assert!((val - 1.8893766604_f64).abs() < 1e-9);
}
}