forked from libre-chip/fayalite
add utility functions for getting smallest integer type that fits a range/value
This commit is contained in:
parent
bdfa18e11d
commit
8080cc7b5c
|
@ -18,7 +18,10 @@ use std::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Bound, Mul, Neg, Not, Range, RangeBounds, Shl, Shr, Sub},
|
ops::{
|
||||||
|
Add, BitAnd, BitOr, BitXor, Bound, Mul, Neg, Not, Range, RangeBounds, RangeInclusive, Shl,
|
||||||
|
Shr, Sub,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Default)]
|
#[derive(Clone, Eq, PartialEq, Hash, Default)]
|
||||||
|
@ -1003,6 +1006,66 @@ impl DynUIntType {
|
||||||
pub fn mask(self) -> BigUint {
|
pub fn mask(self) -> BigUint {
|
||||||
self.modulo() - 1u8
|
self.modulo() - 1u8
|
||||||
}
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `v` losslessly
|
||||||
|
pub fn for_value(v: impl Into<BigUint>) -> Self {
|
||||||
|
let v: BigUint = v.into();
|
||||||
|
Self::new(v.bits().try_into().expect("too big"))
|
||||||
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
|
pub fn range(r: Range<impl Into<BigUint>>) -> Self {
|
||||||
|
let start: BigUint = r.start.into();
|
||||||
|
let end: BigUint = r.end.into();
|
||||||
|
assert!(!end.is_zero(), "empty range");
|
||||||
|
Self::range_inclusive(start..=(end - 1u8))
|
||||||
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
|
pub fn range_inclusive(r: RangeInclusive<impl Into<BigUint>>) -> Self {
|
||||||
|
let (start, end) = r.into_inner();
|
||||||
|
let start: BigUint = start.into();
|
||||||
|
let end: BigUint = end.into();
|
||||||
|
assert!(start <= end, "empty range");
|
||||||
|
// no need to check `start`` since it's no larger than `end`
|
||||||
|
// so must not take more bits than `end`
|
||||||
|
Self::for_value(end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynSIntType {
|
||||||
|
/// gets the smallest `SInt` that fits `v` losslessly
|
||||||
|
pub fn for_value(v: impl Into<BigInt>) -> Self {
|
||||||
|
let v: BigInt = v.into();
|
||||||
|
Self::new(
|
||||||
|
match v.sign() {
|
||||||
|
Sign::Minus => {
|
||||||
|
// account for sign bit and for the minimum value of an `SInt`
|
||||||
|
// being the negative of the maximum value minus one.
|
||||||
|
v.not().bits().checked_add(1).expect("too big")
|
||||||
|
}
|
||||||
|
Sign::NoSign => 0,
|
||||||
|
Sign::Plus => v.bits(),
|
||||||
|
}
|
||||||
|
.try_into()
|
||||||
|
.expect("too big"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/// gets the smallest `SInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
|
pub fn range(r: Range<impl Into<BigInt>>) -> Self {
|
||||||
|
let start: BigInt = r.start.into();
|
||||||
|
let end: BigInt = r.end.into();
|
||||||
|
Self::range_inclusive(start..=(end - 1))
|
||||||
|
}
|
||||||
|
/// gets the smallest `SInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
|
pub fn range_inclusive(r: RangeInclusive<impl Into<BigInt>>) -> Self {
|
||||||
|
let (start, end) = r.into_inner();
|
||||||
|
let start: BigInt = start.into();
|
||||||
|
let end: BigInt = end.into();
|
||||||
|
assert!(start <= end, "empty range");
|
||||||
|
Self::new(Self::for_value(start).width.max(Self::for_value(end).width))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Signed: GenericConstBool> sealed::Sealed for DynIntType<Signed> {}
|
impl<Signed: GenericConstBool> sealed::Sealed for DynIntType<Signed> {}
|
||||||
|
|
Loading…
Reference in a new issue