use std::fmt::Debug;
use crate::{
bitvector::{interval::SignlessInterval, BitvectorBound},
concr::{ConcreteBitvector, SignedBitvector},
};
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct SignedInterval<B: BitvectorBound> {
min: SignedBitvector<B>,
max: SignedBitvector<B>,
}
impl<B: BitvectorBound> SignedInterval<B> {
pub fn new(min: SignedBitvector<B>, max: SignedBitvector<B>) -> Self {
assert!(min <= max);
Self { min, max }
}
pub fn min(&self) -> SignedBitvector<B> {
self.min
}
pub fn max(&self) -> SignedBitvector<B> {
self.max
}
pub fn bound(&self) -> B {
self.min.bound()
}
pub fn from_value(value: SignedBitvector<B>) -> Self {
Self {
min: value,
max: value,
}
}
pub fn try_into_signless(self) -> Option<SignlessInterval<B>> {
if self.min.cast_bitvector().is_sign_bit_set()
== self.max.cast_bitvector().is_sign_bit_set()
{
Some(SignlessInterval::new(
self.min.cast_bitvector(),
self.max.cast_bitvector(),
))
} else {
None
}
}
pub fn ext<X: BitvectorBound>(self, new_bound: X) -> SignedInterval<X> {
if self.min == self.max {
let ext_value = self.min.ext(new_bound);
return SignedInterval {
min: ext_value,
max: ext_value,
};
}
let mut ext_min: SignedBitvector<X> = self.min.ext(new_bound);
let mut ext_max: SignedBitvector<X> = self.max.ext(new_bound);
let min_diff = self.min - ext_min.ext(self.min.bound());
let max_diff = self.max - ext_max.ext(self.max.bound());
if min_diff != max_diff {
ext_min = ConcreteBitvector::new_overhalf(new_bound).as_signed();
ext_max = ConcreteBitvector::new_underhalf(new_bound).as_signed();
}
SignedInterval {
min: ext_min,
max: ext_max,
}
}
#[allow(dead_code)]
pub fn contains_value(&self, value: SignedBitvector<B>) -> bool {
self.min <= value && value <= self.max
}
}
impl<B: BitvectorBound> Debug for SignedInterval<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}]", self.min, self.max)
}
}