#![no_std]
#![cfg_attr(target_arch="avr", feature(asm_experimental_arch))]
pub mod prelude {
pub use crate::Shr3;
pub use crate::Shr3Ops as _;
}
#[cfg(not(feature="__devmode__"))]
mod arch;
#[cfg(feature="__devmode__")]
pub mod arch;
use core::ops::{
Add,
BitOrAssign,
Bound,
RangeBounds,
ShlAssign,
Sub,
};
use core::num::Wrapping;
pub fn shr3(state: u32) -> u32 {
#[cfg(target_arch="avr")]
let state = arch::avr::shr3(state);
#[cfg(not(target_arch="avr"))]
let state = arch::generic::shr3(state);
state
}
pub struct Shr3 {
state: u32,
}
impl Shr3 {
#[inline]
pub const fn new() -> Shr3 {
Self::new_state(1)
}
#[inline]
pub const fn new_state(state: u32) -> Shr3 {
Shr3 {
state: if state == 0 { 0x7FFFFFFF } else { state },
}
}
}
impl Default for Shr3 {
#[inline]
fn default() -> Self {
Self::new()
}
}
pub trait BaseOps: Copy
{
type U;
const NUMBITS: u8;
const MINVAL: Self;
const MAXVAL: Self;
fn from_u8(v: u8) -> Self;
fn from_unsigned(v: Wrapping<Self::U>) -> Self;
fn to_unsigned(&self) -> Wrapping<Self::U>;
fn fls(&self) -> u8;
}
macro_rules! impl_base_ops {
($( ($u:ty, $s:ty) ),*) => {
$(
impl BaseOps for $u {
type U = $u;
const NUMBITS: u8 = <$u>::BITS as u8;
const MINVAL: $u = <$u>::MIN;
const MAXVAL: $u = <$u>::MAX;
#[inline]
fn from_u8(v: u8) -> $u {
v as $u
}
#[inline]
fn from_unsigned(v: Wrapping<Self::U>) -> Self {
v.0
}
#[inline]
fn to_unsigned(&self) -> Wrapping<Self::U> {
Wrapping(*self)
}
#[inline]
fn fls(&self) -> u8 {
(<$u>::BITS - self.leading_zeros()) as u8
}
}
impl BaseOps for $s {
type U = $u;
const NUMBITS: u8 = <$s>::BITS as u8;
const MINVAL: $s = <$s>::MIN;
const MAXVAL: $s = <$s>::MAX;
#[inline]
fn from_u8(v: u8) -> $s {
v as $s
}
#[inline]
fn from_unsigned(v: Wrapping<Self::U>) -> Self {
v.0 as Self
}
#[inline]
fn to_unsigned(&self) -> Wrapping<Self::U> {
Wrapping(*self as Self::U)
}
#[inline]
fn fls(&self) -> u8 {
(<$s>::BITS - self.leading_zeros()) as u8
}
}
)*
}
}
impl_base_ops!((u8, i8), (u16, i16), (u32, i32), (u64, i64), (usize, isize));
#[cfg(has_u128)]
impl_base_ops!((u128, i128));
pub trait Shr3Ops<T>:
where T: BaseOps + Sub<Output=T> + PartialOrd,
T::U: BaseOps,
Wrapping<T::U>: Sub<Output=Wrapping<T::U>> + Add<Output=Wrapping<T::U>> + PartialOrd,
{
fn get_bits(&mut self, bitcount: u8) -> T;
#[inline]
fn get(&mut self) -> T {
self.get_bits(T::NUMBITS)
}
fn get_minmax(&mut self, min_value: T, max_value: T) -> T {
debug_assert!(max_value >= min_value);
let range = max_value.to_unsigned() - min_value.to_unsigned();
let num_bits = range.0.fls();
let value = loop {
let value = self.get_bits(num_bits).to_unsigned();
if value <= range {
break value;
}
};
T::from_unsigned(value + min_value.to_unsigned())
}
#[inline]
fn get_max(&mut self, max_value: T) -> T {
self.get_minmax(T::MINVAL, max_value)
}
fn get_range(&mut self, range: impl RangeBounds<T>) -> T {
let min = match range.start_bound() {
Bound::Included(x) => *x,
Bound::Excluded(_) | Bound::Unbounded => T::MINVAL,
};
let max = match range.end_bound() {
Bound::Included(x) => *x,
Bound::Excluded(x) => {
debug_assert!(*x > T::MINVAL);
*x - T::from_u8(1) },
Bound::Unbounded => T::MAXVAL,
};
self.get_minmax(min, max)
}
}
impl<T> Shr3Ops<T> for Shr3
where T: BaseOps + Sub<Output=T> + PartialOrd,
T::U: BaseOps,
Wrapping<T::U>: Sub<Output=Wrapping<T::U>> + Add<Output=Wrapping<T::U>> + PartialOrd + ShlAssign<usize> + BitOrAssign,
{
fn get_bits(&mut self, bitcount: u8) -> T {
debug_assert!(bitcount <= T::NUMBITS);
let mut ret = T::from_u8(0).to_unsigned();
for _ in 0..bitcount {
self.state = shr3(self.state);
ret <<= 1;
ret |= T::from_u8(self.state as u8 & 1).to_unsigned();
}
T::from_unsigned(ret)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alg() {
assert_eq!(shr3(0), 0);
assert_eq!(shr3(0xFFFF_FFFF), 0x0003E01F);
assert_eq!(shr3(0x5555_5555), 0x000EDFEA);
assert_eq!(shr3(0xAAAA_AAAA), 0x000D3FF5);
assert_eq!(shr3(0x4242_4242), 0x4B4AEFA7);
assert_eq!(shr3(0x3C95_A60C), 0x82D826E6);
}
#[test]
fn test_base_ops() {
assert_eq!(u8::NUMBITS, 8);
assert_eq!(u16::NUMBITS, 16);
assert_eq!(u32::NUMBITS, 32);
assert_eq!(u64::NUMBITS, 64);
assert_eq!(usize::NUMBITS, usize::BITS as u8);
#[cfg(has_u128)]
assert_eq!(u128::NUMBITS, 128);
assert_eq!(i8::NUMBITS, 8);
assert_eq!(i16::NUMBITS, 16);
assert_eq!(i32::NUMBITS, 32);
assert_eq!(i64::NUMBITS, 64);
assert_eq!(isize::NUMBITS, usize::BITS as u8);
#[cfg(has_u128)]
assert_eq!(i128::NUMBITS, 128);
assert_eq!(u8::MINVAL, 0);
assert_eq!(u16::MINVAL, 0);
assert_eq!(u32::MINVAL, 0);
assert_eq!(u64::MINVAL, 0);
assert_eq!(usize::MINVAL, 0);
#[cfg(has_u128)]
assert_eq!(u128::MINVAL, 0);
assert_eq!(i8::MINVAL, i8::MIN);
assert_eq!(i16::MINVAL, i16::MIN);
assert_eq!(i32::MINVAL, i32::MIN);
assert_eq!(i64::MINVAL, i64::MIN);
assert_eq!(isize::MINVAL, isize::MIN);
#[cfg(has_u128)]
assert_eq!(i128::MINVAL, i128::MIN);
assert_eq!(u8::MAXVAL, u8::MAX);
assert_eq!(u16::MAXVAL, u16::MAX);
assert_eq!(u32::MAXVAL, u32::MAX);
assert_eq!(u64::MAXVAL, u64::MAX);
assert_eq!(usize::MAXVAL, usize::MAX);
#[cfg(has_u128)]
assert_eq!(u128::MAXVAL, u128::MAX);
assert_eq!(i8::MAXVAL, i8::MAX);
assert_eq!(i16::MAXVAL, i16::MAX);
assert_eq!(i32::MAXVAL, i32::MAX);
assert_eq!(i64::MAXVAL, i64::MAX);
assert_eq!(isize::MAXVAL, isize::MAX);
#[cfg(has_u128)]
assert_eq!(i128::MAXVAL, i128::MAX);
assert_eq!(u8::from_u8(42), 42);
assert_eq!(u16::from_u8(42), 42);
assert_eq!(u32::from_u8(42), 42);
assert_eq!(u64::from_u8(42), 42);
assert_eq!(usize::from_u8(42), 42);
#[cfg(has_u128)]
assert_eq!(u128::from_u8(42), 42);
assert_eq!(i8::from_u8(42), 42);
assert_eq!(i16::from_u8(42), 42);
assert_eq!(i32::from_u8(42), 42);
assert_eq!(i64::from_u8(42), 42);
assert_eq!(isize::from_u8(42), 42);
#[cfg(has_u128)]
assert_eq!(i128::from_u8(42), 42);
assert_eq!(i8::from_u8(0xFF), -1);
assert_eq!(i16::from_u8(0xFF), 0xFF);
assert_eq!(i32::from_u8(0xFF), 0xFF);
assert_eq!(i64::from_u8(0xFF), 0xFF);
assert_eq!(isize::from_u8(0xFF), 0xFF);
#[cfg(has_u128)]
assert_eq!(i128::from_u8(0xFF), 0xFF);
assert_eq!(u8::from_unsigned(Wrapping(0xF0_u8)), 0xF0);
assert_eq!(u16::from_unsigned(Wrapping(0xF0_u16)), 0xF0);
assert_eq!(u32::from_unsigned(Wrapping(0xF0_u32)), 0xF0);
assert_eq!(u64::from_unsigned(Wrapping(0xF0_u64)), 0xF0);
assert_eq!(usize::from_unsigned(Wrapping(0xF0_usize)), 0xF0);
#[cfg(has_u128)]
assert_eq!(u128::from_unsigned(Wrapping(0xF0_u128)), 0xF0);
assert_eq!(i8::from_unsigned(Wrapping(0xF0_u8)), -16);
assert_eq!(i16::from_unsigned(Wrapping(0xFFF0_u16)), -16);
assert_eq!(i32::from_unsigned(Wrapping(0xFFFF_FFF0_u32)), -16);
assert_eq!(i64::from_unsigned(Wrapping(0xFFFF_FFFF_FFFF_FFF0_u64)), -16);
assert_eq!(isize::from_unsigned(Wrapping((-16_isize) as usize)), -16);
#[cfg(has_u128)]
assert_eq!(i128::from_unsigned(Wrapping((-16_i128) as u128)), -16);
assert_eq!(0xF0_u8.to_unsigned(), Wrapping(0xF0_u8));
assert_eq!(0xF0_u16.to_unsigned(), Wrapping(0xF0_u16));
assert_eq!(0xF0_u32.to_unsigned(), Wrapping(0xF0_u32));
assert_eq!(0xF0_u64.to_unsigned(), Wrapping(0xF0_u64));
assert_eq!(0xF0_usize.to_unsigned(), Wrapping(0xF0_usize));
#[cfg(has_u128)]
assert_eq!(0xF0_u128.to_unsigned(), Wrapping(0xF0_u128));
assert_eq!((-16_i8).to_unsigned(), Wrapping(0xF0_u8));
assert_eq!((-16_i16).to_unsigned(), Wrapping(0xFFF0_u16));
assert_eq!((-16_i32).to_unsigned(), Wrapping(0xFFFF_FFF0_u32));
assert_eq!((-16_i64).to_unsigned(), Wrapping(0xFFFF_FFFF_FFFF_FFF0_u64));
assert_eq!((-16_isize).to_unsigned(), Wrapping((-16_isize) as usize));
#[cfg(has_u128)]
assert_eq!((-16_i128).to_unsigned(), Wrapping((-16_i128) as u128));
assert_eq!(0x00_u8.fls(), 0);
assert_eq!(0x80_u8.fls(), 8);
assert_eq!(0x4F_u8.fls(), 7);
assert_eq!(0x02_u8.fls(), 2);
assert_eq!(0x01_u8.fls(), 1);
assert_eq!(0x4000_u16.fls(), 15);
assert_eq!(0x4000_0000_u32.fls(), 31);
assert_eq!(0x4000_0000_0000_0000_u64.fls(), 63);
#[cfg(has_u128)]
assert_eq!(0x4000_0000_0000_0000_0000_0000_0000_0000_u128.fls(), 127);
assert_eq!(0x00_i8.fls(), 0);
assert_eq!((-127_i8).fls(), 8);
assert_eq!(0x4F_i8.fls(), 7);
assert_eq!(0x02_i8.fls(), 2);
assert_eq!(0x01_i8.fls(), 1);
assert_eq!(0x4000_i16.fls(), 15);
assert_eq!(0x4000_0000_i32.fls(), 31);
assert_eq!(0x4000_0000_0000_0000_i64.fls(), 63);
#[cfg(has_u128)]
assert_eq!(0x4000_0000_0000_0000_0000_0000_0000_0000_i128.fls(), 127);
}
#[test]
fn test_new() {
let a: Shr3 = Default::default();
assert_eq!(a.state, 1);
assert_eq!(Shr3::new().state, 1);
assert_eq!(Shr3::new_state(0).state, 0x7FFF_FFFF);
assert_eq!(Shr3::new_state(1).state, 1);
assert_eq!(Shr3::new_state(42).state, 42);
assert_eq!(Shr3::new_state(0x7FFF_FFFF).state, 0x7FFF_FFFF);
assert_eq!(Shr3::new_state(0xFFFF_FFFF).state, 0xFFFF_FFFF);
}
#[test]
fn test_types() {
{
let mut a = Shr3::new_state(42);
let b: u8 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: u16 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: u32 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: u64 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: usize = a.get_bits(5);
assert_eq!(b, 4);
}
#[cfg(has_u128)]
{
let mut a = Shr3::new_state(42);
let b: u128 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: i8 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: i16 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: i32 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: i64 = a.get_bits(5);
assert_eq!(b, 4);
}
{
let mut a = Shr3::new_state(42);
let b: isize = a.get_bits(5);
assert_eq!(b, 4);
}
#[cfg(has_u128)]
{
let mut a = Shr3::new_state(42);
let b: i128 = a.get_bits(5);
assert_eq!(b, 4);
}
}
#[test]
fn test_get_bits() {
let mut a = Shr3::new_state(42);
for exp in [0x0001, 0x0000, 0x0001, 0x0005, 0x0001, 0x0004] {
let b: u16 = a.get_bits(3);
assert_eq!(b, exp);
}
let b: u16 = a.get_bits(0);
assert_eq!(b, 0);
let mut a = Shr3::new_state(42);
for exp in [0x0001, 0x0000, 0x0001, 0x0005, 0x0001, 0x0004] {
let b: i16 = a.get_bits(3);
assert_eq!(b, exp);
}
let b: i16 = a.get_bits(0);
assert_eq!(b, 0);
}
#[test]
fn test_get() {
let mut a = Shr3::new_state(42);
for exp in [0x20D3, 0x2C5C, 0x2A17, 0xD3C5, 0xAF08, 0x9E5B] {
let b: u16 = a.get();
assert_eq!(b, exp);
}
let mut a = Shr3::new_state(42);
for exp in [0x20D3, 0x2C5C, 0x2A17, 0xD3C5, 0xAF08, 0x9E5B] {
let b: i16 = a.get();
assert_eq!(b as u16, exp as u16);
}
}
#[test]
fn test_max() {
let mut a = Shr3::new_state(42);
for _ in 0..1000 {
let b: u32 = a.get_max(100);
assert!(b <= 100);
}
let b: u32 = a.get_max(0);
assert_eq!(b, 0);
let mut a = Shr3::new_state(42);
for _ in 0..1000 {
let b: i32 = a.get_max(100);
assert!(b <= 100);
}
let b: i32 = a.get_max(0);
assert!(b <= 0);
}
#[test]
fn test_minmax() {
let mut a = Shr3::new_state(42);
for _ in 0..1000 {
let b: u32 = a.get_minmax(60, 170);
assert!((60..=170).contains(&b));
}
let b: u32 = a.get_minmax(111, 111);
assert_eq!(b, 111);
let mut a = Shr3::new_state(42);
for _ in 0..1000 {
let b: i32 = a.get_minmax(-170, 60);
assert!((-170..=60).contains(&b));
}
let b: i32 = a.get_minmax(-111, -111);
assert_eq!(b, -111);
}
#[test]
fn test_range() {
let mut a = Shr3::new_state(42);
for _ in 0..1000 {
let b: u32 = a.get_range(60..170);
assert!((60..170).contains(&b));
}
for _ in 0..1000 {
let b: u32 = a.get_range(60..=170);
assert!((60..=170).contains(&b));
}
for _ in 0..1000 {
let b: u32 = a.get_range(..170);
assert!(b < 170);
}
for _ in 0..1000 {
let b: u32 = a.get_range(..=170);
assert!(b <= 170);
}
for _ in 0..1000 {
let b: u32 = a.get_range(0xFFFF_FFF0..);
assert!(b >= 0xFFFF_FFF0);
}
let b: u32 = a.get_range(111..112);
assert_eq!(b, 111);
let b: u32 = a.get_range(111..=111);
assert_eq!(b, 111);
for _ in 0..1000 {
let b: i32 = a.get_range(-60..170);
assert!((-60..170).contains(&b));
}
for _ in 0..1000 {
let b: i32 = a.get_range(-60..=170);
assert!((-60..=170).contains(&b));
}
for _ in 0..1000 {
let b: i32 = a.get_range(..170);
assert!(b < 170);
}
for _ in 0..1000 {
let b: i32 = a.get_range(..=170);
assert!(b <= 170);
}
for _ in 0..1000 {
let b: i32 = a.get_range(0x7FFF_FFF0..);
assert!(b >= 0x7FFF_FFF0);
}
let b: i32 = a.get_range(-111..-110);
assert_eq!(b, -111);
let b: i32 = a.get_range(-111..=-111);
assert_eq!(b, -111);
}
}