use core::fmt;
use std::num::NonZeroUsize;
use awint::awint_dag::triple_arena::{Advancer, OrdArena, SurjectArena};
use crate::{
ensemble::{PCorrespond, PExternal, PMeta},
Error, EvalAwi, LazyAwi,
};
pub struct Corresponder {
a: OrdArena<PMeta, PExternal, PCorrespond>,
c: SurjectArena<PCorrespond, PMeta, NonZeroUsize>,
}
impl Clone for Corresponder {
fn clone(&self) -> Self {
Self {
a: self.a.clone(),
c: self.c.clone(),
}
}
}
impl fmt::Debug for Corresponder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Corresponder")
.field("a", &self.a)
.field("c", &self.c)
.finish()
}
}
impl Corresponder {
pub fn new() -> Self {
Self {
a: OrdArena::new(),
c: SurjectArena::new(),
}
}
fn get_or_insert_lazy<L: std::borrow::Borrow<LazyAwi>>(
&mut self,
l: &L,
) -> (PCorrespond, NonZeroUsize) {
let l = l.borrow();
let p = l.p_external();
let w = l.nzbw();
(
if let Some(p_meta) = self.a.find_key(&p) {
*self.a.get_val(p_meta).unwrap()
} else {
self.c.insert_with(|p_c| (self.a.insert(p, p_c).0, w))
},
w,
)
}
pub fn correspond_lazy<L0: std::borrow::Borrow<LazyAwi>, L1: std::borrow::Borrow<LazyAwi>>(
&mut self,
l0: &L0,
l1: &L1,
) -> Result<(), Error> {
let (p_c0, w0) = self.get_or_insert_lazy(l0);
let (p_c1, w1) = self.get_or_insert_lazy(l1);
if w0 != w1 {
Err(Error::BitwidthMismatch(w0.get(), w1.get()))
} else {
let _ = self.c.union(p_c0, p_c1);
Ok(())
}
}
fn get_or_insert_eval<E: std::borrow::Borrow<EvalAwi>>(
&mut self,
e: &E,
) -> (PCorrespond, NonZeroUsize) {
let e = e.borrow();
let p = e.p_external();
let w = e.nzbw();
(
if let Some(p_meta) = self.a.find_key(&p) {
*self.a.get_val(p_meta).unwrap()
} else {
self.c.insert_with(|p_c| (self.a.insert(p, p_c).0, w))
},
w,
)
}
pub fn correspond_eval<E0: std::borrow::Borrow<EvalAwi>, E1: std::borrow::Borrow<EvalAwi>>(
&mut self,
e0: &E0,
e1: &E1,
) -> Result<(), Error> {
let (p_c0, w0) = self.get_or_insert_eval(e0);
let (p_c1, w1) = self.get_or_insert_eval(e1);
if w0 != w1 {
Err(Error::BitwidthMismatch(w0.get(), w1.get()))
} else {
let _ = self.c.union(p_c0, p_c1);
Ok(())
}
}
pub fn correspondences_lazy<L: std::borrow::Borrow<LazyAwi>>(
&self,
l: &L,
) -> Result<Vec<LazyAwi>, Error> {
let l = l.borrow();
let p = l.p_external();
if let Some(p_meta) = self.a.find_key(&p) {
let p_start = *self.a.get_val(p_meta).unwrap();
let mut adv = self.c.advancer_surject(p_start);
let mut v = vec![];
while let Some(p_correspond) = adv.advance(&self.c) {
let p_meta = *self.c.get_key(p_correspond).unwrap();
let p_external = *self.a.get_key(p_meta).unwrap();
if p_external != p {
if let Ok(l) = LazyAwi::try_clone_from(p_external, None) {
v.push(l);
}
}
}
Ok(v)
} else {
Err(Error::CorrespondenceNotFound(p))
}
}
pub fn transpose_lazy<L: std::borrow::Borrow<LazyAwi>>(&self, l: &L) -> Result<LazyAwi, Error> {
let tmp = l.borrow();
let p = tmp.p_external();
let mut v = self.correspondences_lazy(&tmp)?;
if v.is_empty() {
return Err(Error::CorrespondenceEmpty(p))
}
if v.len() == 1 {
Ok(v.pop().unwrap())
} else {
Err(Error::CorrespondenceNotATranspose(tmp.p_external()))
}
}
pub fn correspondences_eval<E: std::borrow::Borrow<EvalAwi>>(
&self,
e: &E,
) -> Result<Vec<EvalAwi>, Error> {
let e = e.borrow();
let p = e.p_external();
if let Some(p_meta) = self.a.find_key(&p) {
let p_start = *self.a.get_val(p_meta).unwrap();
let mut adv = self.c.advancer_surject(p_start);
let mut v = vec![];
while let Some(p_correspond) = adv.advance(&self.c) {
let p_meta = *self.c.get_key(p_correspond).unwrap();
let p_external = *self.a.get_key(p_meta).unwrap();
if p_external != p {
if let Ok(l) = EvalAwi::try_clone_from(p_external) {
v.push(l);
}
}
}
Ok(v)
} else {
Err(Error::CorrespondenceNotFound(p))
}
}
pub fn transpose_eval<E: std::borrow::Borrow<EvalAwi>>(&self, e: &E) -> Result<EvalAwi, Error> {
let tmp = e.borrow();
let p = tmp.p_external();
let mut v = self.correspondences_eval(&tmp)?;
if v.is_empty() {
return Err(Error::CorrespondenceEmpty(p))
}
if v.len() == 1 {
Ok(v.pop().unwrap())
} else {
Err(Error::CorrespondenceNotATranspose(tmp.p_external()))
}
}
pub fn correspondences(&self, p_external: PExternal) -> Result<Vec<PExternal>, Error> {
if let Some(p_meta) = self.a.find_key(&p_external) {
let p_start = *self.a.get_val(p_meta).unwrap();
let mut adv = self.c.advancer_surject(p_start);
let mut v = vec![];
while let Some(p_correspond) = adv.advance(&self.c) {
let p_meta = *self.c.get_key(p_correspond).unwrap();
let p_tmp = *self.a.get_key(p_meta).unwrap();
if p_tmp != p_external {
v.push(p_tmp);
}
}
Ok(v)
} else {
Err(Error::CorrespondenceNotFound(p_external))
}
}
}
impl Default for Corresponder {
fn default() -> Self {
Self::new()
}
}