use std::cmp::Ordering;
pub(crate) trait MergeStateRead {
type A;
type B;
fn a_slice(&self) -> &[Self::A];
fn b_slice(&self) -> &[Self::B];
}
pub(crate) type EarlyOut = Option<()>;
pub(crate) trait MergeOperation<M: MergeStateRead> {
fn from_a(&self, m: &mut M, n: usize) -> EarlyOut;
fn from_b(&self, m: &mut M, n: usize) -> EarlyOut;
fn collision(&self, m: &mut M) -> EarlyOut;
fn cmp(&self, a: &M::A, b: &M::B) -> Ordering;
fn merge0(&self, m: &mut M, an: usize, bn: usize) -> EarlyOut {
if an == 0 {
if bn > 0 {
self.from_b(m, bn)?;
}
} else if bn == 0 {
if an > 0 {
self.from_a(m, an)?;
}
} else {
let am: usize = an / 2;
let a = &m.a_slice()[am];
match m.b_slice()[..bn].binary_search_by(|b| self.cmp(a, b).reverse()) {
Ok(bm) => {
self.merge0(m, am, bm)?;
self.collision(m)?;
self.merge0(m, an - am - 1, bn - bm - 1)?;
}
Err(bi) => {
self.merge0(m, am, bi)?;
self.from_a(m, 1)?;
self.merge0(m, an - am - 1, bn - bi)?;
}
}
}
Some(())
}
fn tape_merge(&self, m: &mut M) -> EarlyOut {
while let (Some(a), Some(b)) = (m.a_slice().first(), m.b_slice().first()) {
match self.cmp(a, b) {
Ordering::Greater => {
self.from_b(m, 1)?;
}
Ordering::Less => {
self.from_a(m, 1)?;
}
Ordering::Equal => {
self.collision(m)?;
}
}
}
while let Some(_) = m.a_slice().first() {
self.from_a(m, 1)?;
}
while let Some(_) = m.b_slice().first() {
self.from_b(m, 1)?;
}
Some(())
}
fn merge(&self, m: &mut M) {
let a1 = m.a_slice().len();
let b1 = m.b_slice().len();
self.merge0(m, a1, b1);
}
}