use std::fmt;
use nohash_hasher::IntSet;
use crate::PairTable;
use crate::NAIDX;
use crate::P1KEY;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pair {
i: NAIDX,
j: NAIDX,
}
impl Pair {
pub fn new(i: NAIDX, j: NAIDX) -> Self {
debug_assert!(i < j);
debug_assert!(j < NAIDX::MAX);
Pair { i, j }
}
pub fn i(&self) -> NAIDX {
self.i
}
pub fn j(&self) -> NAIDX {
self.j
}
pub fn key(&self) -> P1KEY {
((self.i as P1KEY) << 16) | (self.j as P1KEY)
}
pub fn from_key(key: P1KEY) -> Self {
let i = (key >> 16) as NAIDX;
let j = (key & 0xFFFF) as NAIDX;
debug_assert!(i < j);
Pair { i, j }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PairSet {
length: usize,
pairs: IntSet<P1KEY>,
}
impl PairSet {
pub fn new(length: usize) -> Self {
Self {
length,
pairs: IntSet::default(),
}
}
pub fn len(&self) -> usize {
self.pairs.len()
}
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
pub fn insert(&mut self, pair: Pair) -> bool {
debug_assert!((pair.j() as usize) < self.length);
self.pairs.insert(pair.key())
}
pub fn contains(&self, pair: &Pair) -> bool {
self.pairs.contains(&pair.key())
}
pub fn iter(&self) -> impl Iterator<Item = Pair> + '_ {
self.pairs.iter().map(|&k| Pair::from_key(k))
}
pub fn to_vec(&self) -> Vec<Pair> {
let mut v: Vec<_> = self.iter().collect();
v.sort_unstable_by_key(|p| (p.i(), p.j()));
v
}
pub fn length(&self) -> usize {
self.length
}
}
impl From<&PairTable> for PairSet {
fn from(pt: &PairTable) -> Self {
let mut pairs = IntSet::default();
for (i, &j_opt) in pt.iter().enumerate() {
let i = i as NAIDX;
if let Some(j) = j_opt {
if i < j {
pairs.insert(Pair::new(i, j).key());
}
}
}
Self {
length: pt.len(),
pairs,
}
}
}
impl fmt::Display for PairSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for pair in self.to_vec() {
if !first {
write!(f, ",")?;
}
write!(f, "({},{})", pair.i(), pair.j())?;
first = false;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pair_key_roundtrip() {
let p = Pair::new(1, 42);
let k = p.key();
let q = Pair::from_key(k);
assert_eq!(p, q);
}
#[test]
fn test_pair_list_from_pair_table() {
let pt = PairTable::try_from("((..))").unwrap();
let pl = PairSet::from(&pt);
let expected = vec![Pair::new(0, 5), Pair::new(1, 4)];
assert_eq!(pl.length(), 6);
assert_eq!(pl.to_vec(), expected);
for p in &expected {
assert!(pl.contains(p));
}
assert!(!pl.contains(&Pair::new(0, 4)));
}
#[test]
fn test_display() {
let pt = PairTable::try_from("((..))").unwrap();
let pl = PairSet::from(&pt);
let s = format!("{}", pl);
assert!(s.contains("(0,5)"));
assert!(s.contains("(1,4)"));
}
}