use std::any::Any;
use std::sync::atomic::{AtomicU32, Ordering};
use crate::value::VBVariant;
use super::backend::RandomBackend;
const MULTIPLIER: u32 = 0x43FD_43FD;
const INCREMENT: u32 = 0x00C3_9EC3;
pub const MODULUS: u32 = 1 << 24;
const SEED_MASK: u32 = MODULUS - 1;
pub const DEFAULT_SEED: u32 = 327_680;
fn next_seed(seed: u32) -> u32 {
seed.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT) & SEED_MASK
}
fn seed_from_negative(value: f32) -> u32 {
let bits = value.to_bits() as u64;
((bits + (bits >> 24)) & SEED_MASK as u64) as u32
}
fn normalize(seed: u32) -> VBVariant {
VBVariant::from_single(seed as f32 / MODULUS as f32)
}
fn splice(bits: u32, current: u32) -> u32 {
let l = bits as i32;
let mixed = ((l & 0xFFFF) ^ (l >> 16)) as u32;
(current & 0xFF00_00FF) | (mixed << 8)
}
pub struct ClassicBackend {
seed: AtomicU32,
}
impl ClassicBackend {
pub fn new() -> Self {
Self::with_seed(DEFAULT_SEED)
}
pub fn with_seed(seed: u32) -> Self {
Self {
seed: AtomicU32::new(seed),
}
}
pub fn seed(&self) -> u32 {
self.seed.load(Ordering::Relaxed)
}
pub fn set_seed(&self, value: u32) {
self.seed.store(value, Ordering::Relaxed);
}
}
impl Default for ClassicBackend {
fn default() -> Self {
Self::new()
}
}
impl RandomBackend for ClassicBackend {
fn as_any(&self) -> &dyn Any {
self
}
fn next(&mut self) -> VBVariant {
let next = next_seed(self.seed());
self.set_seed(next);
normalize(next)
}
fn current(&self) -> VBVariant {
normalize(self.seed())
}
fn seed_from_rnd_argument(&mut self, value: f32) -> VBVariant {
let seeded = seed_from_negative(value);
let next = next_seed(seeded);
self.set_seed(next);
normalize(next)
}
fn randomize(&mut self, bits: u32) {
let current = self.seed();
self.set_seed(splice(bits, current));
}
}