pub mod extsizes;
pub use self::extsizes::*;
use super::multiplier::*;
use super::numops::*;
use super::outputmix::*;
use super::seeds::PcgSeeder;
use super::stream::*;
use super::PcgEngine;
use num_traits::{One, Zero};
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use rand_core::{RngCore, SeedableRng};
use std::marker::PhantomData;
pub struct ExtPcg<
Itype,
Xtype,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
Size: ExtSize,
> {
pcg: PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>,
ext: Vec<Xtype>,
_size: PhantomData<Size>,
}
impl<Itype, Xtype, StreamMix, MulMix, OutMix, Size>
ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size>
where
Itype: Zero + One,
Xtype: PcgOps + BitSize,
Standard: Distribution<Xtype>,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
Size: ExtSize,
PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>: Rng + SeedableRng,
{
pub fn from_pcg(
pcg: PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>,
) -> ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size> {
let mut pcg = pcg;
let mut ext = Vec::with_capacity(Size::EXT_SIZE);
for _ in 0..Size::EXT_SIZE {
ext.push(pcg.gen());
}
ExtPcg {
pcg,
ext,
_size: PhantomData::<Size>,
}
}
}
impl<Itype, Xtype, StreamMix, MulMix, OutMix, Size>
ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size>
where
Itype: Zero + One,
Xtype: PcgOps + BitSize,
Standard: Distribution<Xtype>,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
Size: ExtSize,
PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>: Rng + SeedableRng,
PcgSeeder<Itype>: Default,
{
pub fn new_unseeded() -> ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size> {
let pcg = PcgEngine::<Itype, Xtype, StreamMix, MulMix, OutMix>::new_unseeded();
Self::from_pcg(pcg)
}
}
impl<Itype, StreamMix, MulMix, OutMix, Size> RngCore
for ExtPcg<Itype, u32, StreamMix, MulMix, OutMix, Size>
where
Itype: PcgOps + AsUsize + BitSize + AsSmaller<u32> + Clone,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, u32>,
Size: ExtSize,
{
#[inline]
fn next_u32(&mut self) -> u32 {
let oldstate = self.pcg.state.clone();
self.pcg.state = self
.pcg
.stream_mix
.increment()
.wrap_add(oldstate.wrap_mul(MulMix::multiplier()));
let mask = 2usize.pow(Size::EXT_BITS) - 1;
let pick = self.pcg.state.as_usize() & mask;
let ext_val = self.ext[pick];
self.ext[pick] += 1;
OutMix::output(
oldstate,
self.pcg.stream_mix.increment(),
MulMix::multiplier(),
) ^ ext_val
}
fn next_u64(&mut self) -> u64 {
::rand_core::impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
::rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ::rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<Itype, StreamMix, MulMix, OutMix, Size> RngCore
for ExtPcg<Itype, u64, StreamMix, MulMix, OutMix, Size>
where
Itype: PcgOps + AsUsize + BitSize + AsSmaller<u64> + Clone,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, u64>,
Size: ExtSize,
{
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
let oldstate = self.pcg.state.clone();
self.pcg.state = self
.pcg
.stream_mix
.increment()
.wrap_add(oldstate.wrap_mul(MulMix::multiplier()));
let mask = 2usize.pow(Size::EXT_BITS) - 1;
let pick = self.pcg.state.as_usize() & mask;
let ext_val = self.ext[pick];
self.ext[pick] += 1;
OutMix::output(
oldstate,
self.pcg.stream_mix.increment(),
MulMix::multiplier(),
) ^ ext_val
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
::rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ::rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
pub type SetseqXshRr6432ext<Size> =
ExtPcg<u64, u32, SpecificSeqStream<u64>, DefaultMultiplier, XshRrMixin, Size>;
pub type SetseqXshRr12832ext<Size> =
ExtPcg<u128, u32, SpecificSeqStream<u128>, DefaultMultiplier, XshRrMixin, Size>;
pub type SetseqXshRr12864ext<Size> =
ExtPcg<u128, u64, SpecificSeqStream<u128>, DefaultMultiplier, XshRrMixin, Size>;
pub type Pcg32Ext<Size> = SetseqXshRr6432ext<Size>;
pub type Pcg32LExt<Size> = SetseqXshRr12832ext<Size>;
pub type Pcg64Ext<Size> = SetseqXshRr12864ext<Size>;
impl<Itype, Xtype, StreamMix, MulMix, OutMix, Size> SeedableRng
for ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size>
where
Itype: ::seeds::ReadByteOrder + Default + Zero + One,
Xtype: PcgOps + BitSize,
Standard: Distribution<Xtype>,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
Size: ExtSize,
ExtPcg<Itype, Xtype, StreamMix, MulMix, OutMix, Size>: RngCore,
PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>:
RngCore + SeedableRng<Seed = PcgSeeder<Itype>>,
PcgSeeder<Itype>: Default,
{
type Seed = PcgSeeder<Itype>;
fn from_seed(seed: Self::Seed) -> Self {
let pcg = PcgEngine::from_seed(seed);
ExtPcg::from_pcg(pcg)
}
}