use crate::{
bitvector::{
abstr::dual_interval::DualInterval,
interval::{
SignedInterval, SignlessInterval, UnsignedInterval, WrappingInterpretation,
WrappingInterval,
},
},
concr::ConcreteBitvector,
misc::BitvectorBound,
};
impl<B: BitvectorBound> DualInterval<B> {
pub(super) fn opt_halves(self) -> (Option<SignlessInterval<B>>, Option<SignlessInterval<B>>) {
if self.near_half == self.far_half {
if self.near_half.is_sign_bit_set() {
(None, Some(self.far_half))
} else {
(Some(self.near_half), None)
}
} else {
(Some(self.near_half), Some(self.far_half))
}
}
pub(super) fn try_from_opt_halves(
near_half: Option<SignlessInterval<B>>,
far_half: Option<SignlessInterval<B>>,
) -> Option<Self> {
let (near_half, far_half) = match (near_half, far_half) {
(None, None) => return None,
(None, Some(far_half)) => (far_half, far_half),
(Some(near_half), None) => (near_half, near_half),
(Some(near_half), Some(far_half)) => {
assert_eq!(near_half.bound(), far_half.bound());
(near_half, far_half)
}
};
Some(Self {
near_half,
far_half,
})
}
pub(super) fn from_opt_halves(
near_half: Option<SignlessInterval<B>>,
far_half: Option<SignlessInterval<B>>,
) -> Self {
Self::try_from_opt_halves(near_half, far_half)
.expect("At least one half should be supplied")
}
}
pub fn wrapping_halves<B: BitvectorBound>(
interval: WrappingInterval<B>,
) -> (Option<SignlessInterval<B>>, Option<SignlessInterval<B>>) {
let bound = interval.bound();
let interpreted = interval.interpret();
match interpreted {
WrappingInterpretation::Signless(interval) => {
let far_half = interval.min().is_sign_bit_set();
if far_half {
(None, Some(interval))
} else {
(Some(interval), None)
}
}
WrappingInterpretation::Unsigned(interval) => (
Some(SignlessInterval::new(
interval.min().cast_bitvector(),
ConcreteBitvector::<B>::new_underhalf(bound),
)),
Some(SignlessInterval::new(
ConcreteBitvector::<B>::new_overhalf(bound),
interval.max().cast_bitvector(),
)),
),
WrappingInterpretation::Signed(interval) => (
Some(SignlessInterval::new(
ConcreteBitvector::<B>::zero(interval.bound()),
interval.max().cast_bitvector(),
)),
Some(SignlessInterval::new(
interval.min().cast_bitvector(),
ConcreteBitvector::<B>::new_umax(bound),
)),
),
}
}
pub fn unsigned_halves<B: BitvectorBound>(
interval: UnsignedInterval<B>,
) -> (Option<SignlessInterval<B>>, Option<SignlessInterval<B>>) {
let bound = interval.bound();
match interval.try_into_signless() {
Some(interval) => {
let far_half = interval.is_sign_bit_set();
if far_half {
(None, Some(interval))
} else {
(Some(interval), None)
}
}
None => (
Some(SignlessInterval::new(
interval.min().cast_bitvector(),
ConcreteBitvector::<B>::new_underhalf(bound),
)),
Some(SignlessInterval::new(
ConcreteBitvector::<B>::new_overhalf(bound),
interval.max().cast_bitvector(),
)),
),
}
}
pub fn signed_halves<B: BitvectorBound>(
interval: SignedInterval<B>,
) -> (Option<SignlessInterval<B>>, Option<SignlessInterval<B>>) {
let bound = interval.bound();
match interval.try_into_signless() {
Some(interval) => {
let far_half = interval.is_sign_bit_set();
if far_half {
(None, Some(interval))
} else {
(Some(interval), None)
}
}
None => (
Some(SignlessInterval::new(
ConcreteBitvector::<B>::zero(bound),
interval.max().cast_bitvector(),
)),
Some(SignlessInterval::new(
interval.min().cast_bitvector(),
ConcreteBitvector::<B>::new_umax(bound),
)),
),
}
}