use std::fmt::{Debug, Display};
use serde::{Deserialize, Serialize};
use crate::{
bitvector::{
interval::{SignedInterval, UnsignedInterval, WrappingInterval},
BitvectorBound,
},
concr::ConcreteBitvector,
misc::{CBound, RBound},
};
#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct SignlessInterval<B: BitvectorBound> {
min: ConcreteBitvector<B>,
max: ConcreteBitvector<B>,
}
impl<B: BitvectorBound> SignlessInterval<B> {
pub fn new(min: ConcreteBitvector<B>, max: ConcreteBitvector<B>) -> Self {
assert_eq!(min.is_sign_bit_set(), max.is_sign_bit_set());
assert!(min.as_unsigned() <= max.as_unsigned());
Self { min, max }
}
pub fn from_value(value: ConcreteBitvector<B>) -> Self {
Self {
min: value,
max: value,
}
}
pub fn bound(&self) -> B {
self.min.bound()
}
pub fn is_sign_bit_set(&self) -> bool {
self.min.is_sign_bit_set()
}
pub(crate) fn new_full_near_halfplane(bound: B) -> Self {
Self {
min: ConcreteBitvector::<B>::zero(bound),
max: ConcreteBitvector::<B>::new_underhalf(bound),
}
}
pub(crate) fn new_full_far_halfplane(bound: B) -> Self {
Self {
min: ConcreteBitvector::<B>::new_overhalf(bound),
max: ConcreteBitvector::<B>::new_umax(bound),
}
}
pub fn contains_value(&self, value: &ConcreteBitvector<B>) -> bool {
let value = value.as_unsigned();
self.min.as_unsigned() <= value && value <= self.max.as_unsigned()
}
pub fn concrete_value(&self) -> Option<ConcreteBitvector<B>> {
if self.min == self.max {
return Some(self.min);
}
None
}
pub fn intersection(self, other: Self) -> Option<Self> {
assert_eq!(self.bound(), other.bound());
assert_eq!(self.min.is_sign_bit_set(), other.min.is_sign_bit_set());
let min = self.min.as_unsigned().max(other.min.as_unsigned());
let max = self.max.as_unsigned().min(other.max.as_unsigned());
if min <= max {
Some(Self {
min: min.cast_bitvector(),
max: max.cast_bitvector(),
})
} else {
None
}
}
pub fn union(self, other: Self) -> Self {
assert_eq!(self.bound(), other.bound());
assert_eq!(self.min.is_sign_bit_set(), other.min.is_sign_bit_set());
Self {
min: self
.min
.as_unsigned()
.min(other.min.as_unsigned())
.cast_bitvector(),
max: self
.max
.as_unsigned()
.max(other.max.as_unsigned())
.cast_bitvector(),
}
}
pub fn union_opt(a: Option<Self>, b: Option<Self>) -> Option<Self> {
match (a, b) {
(None, None) => None,
(None, Some(b)) => Some(b),
(Some(a), None) => Some(a),
(Some(a), Some(b)) => Some(a.union(b)),
}
}
pub fn min(&self) -> ConcreteBitvector<B> {
self.min
}
pub fn max(&self) -> ConcreteBitvector<B> {
self.max
}
pub fn into_wrapping(self) -> WrappingInterval<B> {
WrappingInterval::new(self.min, self.max)
}
pub fn into_unsigned(self) -> UnsignedInterval<B> {
UnsignedInterval::new(self.min.as_unsigned(), self.max.as_unsigned())
}
pub fn into_signed(self) -> SignedInterval<B> {
SignedInterval::new(self.min.as_signed(), self.max.as_signed())
}
#[allow(dead_code)]
pub fn all_with_bound_iter(bound: B, far: bool) -> impl Iterator<Item = Self> {
let min_iter = ConcreteBitvector::<B>::all_with_bound_iter(bound);
min_iter
.flat_map(move |min| {
if min.is_sign_bit_set() != far {
return None;
}
let max_iter = ConcreteBitvector::<B>::all_with_bound_iter(bound);
let result = max_iter.flat_map(move |max| {
if max.is_sign_bit_set() != far {
return None;
}
if min.to_u64() > max.to_u64() {
return None;
}
Some(SignlessInterval::new(min, max))
});
Some(result)
})
.flatten()
}
#[allow(dead_code)]
pub fn contains(&self, other: &Self) -> bool {
if self.min.is_sign_bit_set() != other.min.is_sign_bit_set() {
return false;
}
self.min.as_unsigned() <= other.min.as_unsigned()
&& other.max.as_unsigned() <= self.max.as_unsigned()
}
}
impl<B: BitvectorBound> Debug for SignlessInterval<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}]", self.min, self.max)
}
}
impl<B: BitvectorBound> Display for SignlessInterval<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self, f)
}
}
impl<const W: u32> SignlessInterval<CBound<W>> {
pub(crate) fn from_runtime(value: SignlessInterval<RBound>) -> Self {
Self {
min: ConcreteBitvector::from_runtime_bitvector(value.min),
max: ConcreteBitvector::from_runtime_bitvector(value.max),
}
}
pub(crate) fn to_runtime(self) -> SignlessInterval<RBound> {
SignlessInterval {
min: self.min.as_runtime_bitvector(),
max: self.max.as_runtime_bitvector(),
}
}
}