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,
|
||||
hash::Hash,
|
||||
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)]
|
||||
|
@ -1003,6 +1006,66 @@ impl DynUIntType {
|
|||
pub fn mask(self) -> BigUint {
|
||||
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> {}
|
||||
|
|
Loading…
Reference in a new issue