#![doc = include_str!("../README.md")]
#[cfg(test)]
mod test;
use core::cmp::Ordering;
pub trait MergeState {
type A;
type B;
fn a_slice(&self) -> &[Self::A];
fn b_slice(&self) -> &[Self::B];
}
pub trait MergeOperation<M: MergeState> {
fn from_a(&self, m: &mut M, n: usize) -> bool;
fn from_b(&self, m: &mut M, n: usize) -> bool;
fn collision(&self, m: &mut M) -> bool;
fn cmp(&self, a: &M::A, b: &M::B) -> Ordering;
fn binary_merge(&self, m: &mut M, an: usize, bn: usize) -> bool {
if an == 0 {
bn == 0 || self.from_b(m, bn)
} else if bn == 0 {
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.binary_merge(m, am, bm) &&
self.collision(m) &&
self.binary_merge(m, an - am - 1, bn - bm - 1)
}
Err(bi) => {
self.binary_merge(m, am, bi) &&
self.from_a(m, 1) &&
self.binary_merge(m, an - am - 1, bn - bi)
}
}
}
}
fn tape_merge(&self, m: &mut M) -> bool {
loop {
if let Some(a) = m.a_slice().first() {
if let Some(b) = m.b_slice().first() {
if !match self.cmp(a, b) {
Ordering::Less => self.from_a(m, 1),
Ordering::Equal => self.collision(m),
Ordering::Greater => self.from_b(m, 1),
} {
return false;
}
} else {
break m.a_slice().is_empty() || self.from_a(m, m.a_slice().len());
}
} else {
break m.b_slice().is_empty() || self.from_b(m, m.b_slice().len());
}
}
}
fn merge(&self, m: &mut M) -> bool {
let an = m.a_slice().len();
let bn = m.b_slice().len();
if an > Self::MCM_THRESHOLD || bn > Self::MCM_THRESHOLD {
self.binary_merge(m, an, bn)
} else {
self.tape_merge(m)
}
}
const MCM_THRESHOLD: usize = 8;
}