use crate::Tmr;
use super::Final;
use std::cell::RefCell;
use std::sync::Arc;
const N_POWERS: usize = Tmr::TWO_TWO_N.len();
const N_BUFFERS: usize = Tmr::BUFFER8_TWO_N_PLUS_ONE.len();
thread_local! {
static TWO_TWO_N: RefCell<Option<[Arc<Final>; N_POWERS]>> = const { RefCell::new(None) };
static BUFFER8_TWO_N_PLUS_ONE: RefCell<Option<[Arc<Final>; N_BUFFERS]>> = const { RefCell::new(None) };
static CTX8: RefCell<Option<Arc<Final>>> = const { RefCell::new(None) };
}
fn initialize(write: &mut Option<[Arc<Final>; N_POWERS]>) {
let one = Final::unit();
let mut power = Final::sum(Arc::clone(&one), one);
*write = Some(core::array::from_fn(|i| {
if i > 0 {
power = Final::product(Arc::clone(&power), Arc::clone(&power));
}
Arc::clone(&power)
}));
}
pub fn nth_power_of_2(n: usize) -> Arc<Final> {
TWO_TWO_N.with(|arr| {
if arr.borrow().is_none() {
initialize(&mut arr.borrow_mut());
}
debug_assert!(arr.borrow().is_some());
Arc::clone(&arr.borrow().as_ref().unwrap()[n])
})
}
fn initialize_buffers(write: &mut Option<[Arc<Final>; N_BUFFERS]>) {
let mut buf = nth_power_of_2(3).successor();
*write = Some(core::array::from_fn(|i| {
if i > 0 {
buf = Final::product(
Final::two_two_n(i + 3).unwrap().successor(),
Arc::clone(&buf),
);
}
Arc::clone(&buf)
}));
}
pub fn buffer8_two_n_plus_one(n: usize) -> Arc<Final> {
BUFFER8_TWO_N_PLUS_ONE.with(|arr| {
if arr.borrow().is_none() {
initialize_buffers(&mut arr.borrow_mut());
}
debug_assert!(arr.borrow().is_some());
Arc::clone(&arr.borrow().as_ref().unwrap()[n])
})
}
pub fn ctx8() -> Arc<Final> {
CTX8.with(|opt| {
if opt.borrow().is_none() {
*opt.borrow_mut() = Some(Final::product(
buffer8_two_n_plus_one(5),
Final::product(
Final::two_two_n_fixed::<6>(), Final::two_two_n_fixed::<8>(), ),
));
}
debug_assert!(opt.borrow().is_some());
Arc::clone(opt.borrow().as_ref().unwrap())
})
}