use std::collections::BTreeSet;
use crate::basic::persistent_btree::{EMPTY_ROOT, NodeId, PersistentBTree};
pub fn three_way_merge(
tree: &mut PersistentBTree,
ancestor_root: NodeId,
source_root: NodeId,
target_root: NodeId,
) -> NodeId {
if ancestor_root == source_root {
return target_root;
}
if ancestor_root == target_root {
return source_root;
}
if source_root == target_root {
return source_root;
}
let mut iter_a = tree.iter(ancestor_root).peekable();
let mut iter_s = tree.iter(source_root).peekable();
let mut iter_t = tree.iter(target_root).peekable();
let mut merged: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
loop {
let ka = iter_a.peek().map(|(k, _)| k.as_slice());
let ks = iter_s.peek().map(|(k, _)| k.as_slice());
let kt = iter_t.peek().map(|(k, _)| k.as_slice());
if ka.is_none() && ks.is_none() && kt.is_none() {
break;
}
let min_key = [ka, ks, kt].into_iter().flatten().min().unwrap().to_vec();
let a_val = if ka == Some(min_key.as_slice()) {
let (_, v) = iter_a.next().unwrap();
Some(v)
} else {
None
};
let s_val = if ks == Some(min_key.as_slice()) {
let (_, v) = iter_s.next().unwrap();
Some(v)
} else {
None
};
let t_val = if kt == Some(min_key.as_slice()) {
let (_, v) = iter_t.next().unwrap();
Some(v)
} else {
None
};
let result = decide(a_val.as_deref(), s_val.as_deref(), t_val.as_deref());
if let Some(val) = result {
merged.push((min_key, val.to_vec()));
}
}
tree.bulk_load(merged)
}
pub fn three_way_merge_many_bases(
tree: &mut PersistentBTree,
ancestor_roots: &[NodeId],
source_root: NodeId,
target_root: NodeId,
) -> NodeId {
if ancestor_roots.len() <= 1 {
return three_way_merge(
tree,
ancestor_roots.first().copied().unwrap_or(EMPTY_ROOT),
source_root,
target_root,
);
}
if source_root == target_root {
return source_root;
}
let mut keys = BTreeSet::new();
for root in ancestor_roots
.iter()
.copied()
.chain([source_root, target_root])
{
for (key, _) in tree.iter(root) {
keys.insert(key);
}
}
let mut merged = Vec::new();
for key in keys {
let base_values: Vec<Option<Vec<u8>>> = ancestor_roots
.iter()
.map(|&root| tree.get(root, &key))
.collect();
let first_base = base_values.first().cloned().unwrap_or(None);
let source = tree.get(source_root, &key);
let target = tree.get(target_root, &key);
let result = if base_values.iter().all(|base| base == &first_base) {
decide(first_base.as_deref(), source.as_deref(), target.as_deref())
.map(<[u8]>::to_vec)
} else {
source
};
if let Some(value) = result {
merged.push((key, value));
}
}
tree.bulk_load(merged)
}
fn decide<'a>(
ancestor: Option<&'a [u8]>,
source: Option<&'a [u8]>,
target: Option<&'a [u8]>,
) -> Option<&'a [u8]> {
match (ancestor, source, target) {
(Some(a), Some(s), Some(t)) if a == s && a == t => Some(a),
(Some(a), Some(s), Some(t)) if a == t => Some(s),
(Some(a), Some(s), Some(t)) if a == s => Some(t),
(Some(_), Some(s), Some(t)) if s == t => Some(s),
(Some(_), Some(s), Some(_)) => Some(s),
(Some(a), None, Some(t)) if a == t => None,
(Some(a), Some(s), None) if a == s => None,
(Some(_), None, Some(_)) => None,
(Some(_), Some(s), None) => Some(s),
(Some(_), None, None) => None,
(None, Some(s), None) => Some(s),
(None, None, Some(t)) => Some(t),
(None, Some(s), Some(t)) if s == t => Some(s),
(None, Some(s), Some(_)) => Some(s),
(None, None, None) => None,
}
}