use std::fmt::Debug;
use std::marker;
use std::ops::Range;
use snapshot_vec::{self as sv, UndoLog};
use undo_log::{UndoLogs, VecLog};
mod backing_vec;
pub use self::backing_vec::{
Delegate, InPlace, UnificationStore, UnificationStoreBase, UnificationStoreMut,
};
#[cfg(feature = "persistent")]
pub use self::backing_vec::Persistent;
#[cfg(test)]
mod tests;
pub trait UnifyKey: Copy + Clone + Debug + PartialEq {
type Value: UnifyValue;
fn index(&self) -> u32;
fn from_index(u: u32) -> Self;
fn tag() -> &'static str;
#[allow(unused_variables)]
fn order_roots(
a: Self,
a_value: &Self::Value,
b: Self,
b_value: &Self::Value,
) -> Option<(Self, Self)> {
None
}
}
pub trait UnifyValue: Clone + Debug {
type Error;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error>;
}
pub trait EqUnifyValue: Eq + Clone + Debug {}
impl<T: EqUnifyValue> UnifyValue for T {
type Error = (T, T);
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
if value1 == value2 {
Ok(value1.clone())
} else {
Err((value1.clone(), value2.clone()))
}
}
}
#[derive(Debug)]
pub struct NoError {
_dummy: (),
}
#[derive(PartialEq, Clone, Debug)]
pub struct VarValue<K: UnifyKey> {
parent: K, value: K::Value, rank: u32, }
#[derive(Clone, Debug, Default)]
pub struct UnificationTable<S: UnificationStoreBase> {
values: S,
}
pub type UnificationStorage<K> = Vec<VarValue<K>>;
pub type UnificationTableStorage<K> = UnificationTable<InPlace<K, UnificationStorage<K>, ()>>;
#[allow(type_alias_bounds)]
pub type InPlaceUnificationTable<
K: UnifyKey,
V: sv::VecLike<Delegate<K>> = Vec<VarValue<K>>,
L = VecLog<UndoLog<Delegate<K>>>,
> = UnificationTable<InPlace<K, V, L>>;
#[cfg(feature = "persistent")]
#[allow(type_alias_bounds)]
pub type PersistentUnificationTable<K: UnifyKey> = UnificationTable<Persistent<K>>;
pub struct Snapshot<S: UnificationStore> {
marker: marker::PhantomData<S>,
snapshot: S::Snapshot,
}
impl<K: UnifyKey> VarValue<K> {
fn new_var(key: K, value: K::Value) -> VarValue<K> {
VarValue::new(key, value, 0)
}
fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
VarValue {
parent: parent, value: value,
rank: rank,
}
}
fn redirect(&mut self, to: K) {
self.parent = to;
}
fn root(&mut self, rank: u32, value: K::Value) {
self.rank = rank;
self.value = value;
}
}
impl<K> UnificationTableStorage<K>
where
K: UnifyKey,
{
pub fn with_log<'a, L>(
&'a mut self,
undo_log: L,
) -> UnificationTable<InPlace<K, &'a mut UnificationStorage<K>, L>>
where
L: UndoLogs<sv::UndoLog<Delegate<K>>>,
{
UnificationTable {
values: InPlace {
values: self.values.values.with_log(undo_log),
},
}
}
}
impl<S: UnificationStoreBase + Default> UnificationTable<S> {
pub fn new() -> Self {
Self::default()
}
}
impl<S: UnificationStore> UnificationTable<S> {
pub fn snapshot(&mut self) -> Snapshot<S> {
Snapshot {
marker: marker::PhantomData::<S>,
snapshot: self.values.start_snapshot(),
}
}
pub fn rollback_to(&mut self, snapshot: Snapshot<S>) {
debug!("{}: rollback_to()", S::tag());
self.values.rollback_to(snapshot.snapshot);
}
pub fn commit(&mut self, snapshot: Snapshot<S>) {
debug!("{}: commit()", S::tag());
self.values.commit(snapshot.snapshot);
}
pub fn vars_since_snapshot(&self, snapshot: &Snapshot<S>) -> Range<S::Key> {
let range = self.values.values_since_snapshot(&snapshot.snapshot);
S::Key::from_index(range.start as u32)..S::Key::from_index(range.end as u32)
}
}
impl<S: UnificationStoreBase> UnificationTable<S> {
pub fn len(&self) -> usize {
self.values.len()
}
fn value(&self, key: S::Key) -> &VarValue<S::Key> {
&self.values[key.index() as usize]
}
}
impl<S: UnificationStoreMut> UnificationTable<S> {
pub fn new_key(&mut self, value: S::Value) -> S::Key {
let len = self.values.len();
let key: S::Key = UnifyKey::from_index(len as u32);
self.values.push(VarValue::new_var(key, value));
debug!("{}: created new key: {:?}", S::tag(), key);
key
}
pub fn reserve(&mut self, num_new_keys: usize) {
self.values.reserve(num_new_keys);
}
pub fn reset_unifications(&mut self, mut value: impl FnMut(S::Key) -> S::Value) {
self.values.reset_unifications(|i| {
let key = UnifyKey::from_index(i as u32);
let value = value(key);
VarValue::new_var(key, value)
});
}
#[inline(always)]
fn inlined_get_root_key(&mut self, vid: S::Key) -> S::Key {
let v = self.value(vid);
if v.parent == vid {
return vid;
}
let redirect = v.parent;
let root_key: S::Key = self.uninlined_get_root_key(redirect);
if root_key != redirect {
self.update_value(vid, |value| value.parent = root_key);
}
root_key
}
#[inline(never)]
fn uninlined_get_root_key(&mut self, vid: S::Key) -> S::Key {
self.inlined_get_root_key(vid)
}
fn update_value<OP>(&mut self, key: S::Key, op: OP)
where
OP: FnOnce(&mut VarValue<S::Key>),
{
self.values.update(key.index() as usize, op);
debug!("Updated variable {:?} to {:?}", key, self.value(key));
}
fn unify_roots(&mut self, key_a: S::Key, key_b: S::Key, new_value: S::Value) {
debug!("unify(key_a={:?}, key_b={:?})", key_a, key_b);
let rank_a = self.value(key_a).rank;
let rank_b = self.value(key_b).rank;
if let Some((new_root, redirected)) = S::Key::order_roots(
key_a,
&self.value(key_a).value,
key_b,
&self.value(key_b).value,
) {
let new_rank = if new_root == key_a {
debug_assert!(redirected == key_b);
if rank_a > rank_b {
rank_a
} else {
rank_b + 1
}
} else {
debug_assert!(new_root == key_b);
debug_assert!(redirected == key_a);
if rank_b > rank_a {
rank_b
} else {
rank_a + 1
}
};
self.redirect_root(new_rank, redirected, new_root, new_value);
} else if rank_a > rank_b {
self.redirect_root(rank_a, key_b, key_a, new_value);
} else if rank_a < rank_b {
self.redirect_root(rank_b, key_a, key_b, new_value);
} else {
self.redirect_root(rank_a + 1, key_a, key_b, new_value);
}
}
fn redirect_root(
&mut self,
new_rank: u32,
old_root_key: S::Key,
new_root_key: S::Key,
new_value: S::Value,
) {
self.update_value(old_root_key, |old_root_value| {
old_root_value.redirect(new_root_key);
});
self.update_value(new_root_key, |new_root_value| {
new_root_value.root(new_rank, new_value);
});
}
}
impl<S, K, V> UnificationTable<S>
where
S: UnificationStoreBase<Key = K, Value = V>,
K: UnifyKey<Value = V>,
V: UnifyValue,
{
#[inline]
pub fn try_probe_value<'a, K1>(&'a self, id: K1) -> Option<&'a V>
where
K1: Into<K>,
K: 'a,
{
let id = id.into();
let v = self.value(id);
if v.parent == id {
return Some(&v.value);
}
None
}
}
impl<S, K, V> UnificationTable<S>
where
S: UnificationStoreMut<Key = K, Value = V>,
K: UnifyKey<Value = V>,
V: UnifyValue,
{
pub fn union<K1, K2>(&mut self, a_id: K1, b_id: K2)
where
K1: Into<K>,
K2: Into<K>,
V: UnifyValue<Error = NoError>,
{
self.unify_var_var(a_id, b_id).unwrap();
}
pub fn union_value<K1>(&mut self, id: K1, value: V)
where
K1: Into<K>,
V: UnifyValue<Error = NoError>,
{
self.unify_var_value(id, value).unwrap();
}
pub fn unioned<K1, K2>(&mut self, a_id: K1, b_id: K2) -> bool
where
K1: Into<K>,
K2: Into<K>,
{
self.find(a_id) == self.find(b_id)
}
pub fn find<K1>(&mut self, id: K1) -> K
where
K1: Into<K>,
{
let id = id.into();
self.uninlined_get_root_key(id)
}
pub fn unify_var_var<K1, K2>(&mut self, a_id: K1, b_id: K2) -> Result<(), V::Error>
where
K1: Into<K>,
K2: Into<K>,
{
let a_id = a_id.into();
let b_id = b_id.into();
let root_a = self.uninlined_get_root_key(a_id);
let root_b = self.uninlined_get_root_key(b_id);
if root_a == root_b {
return Ok(());
}
let combined = V::unify_values(&self.value(root_a).value, &self.value(root_b).value)?;
Ok(self.unify_roots(root_a, root_b, combined))
}
pub fn unify_var_value<K1>(&mut self, a_id: K1, b: V) -> Result<(), V::Error>
where
K1: Into<K>,
{
let a_id = a_id.into();
let root_a = self.uninlined_get_root_key(a_id);
let value = V::unify_values(&self.value(root_a).value, &b)?;
self.update_value(root_a, |node| node.value = value);
Ok(())
}
pub fn probe_value<K1>(&mut self, id: K1) -> V
where
K1: Into<K>,
{
self.inlined_probe_value(id)
}
#[inline(always)]
pub fn inlined_probe_value<K1>(&mut self, id: K1) -> V
where
K1: Into<K>,
{
let id = id.into();
let id = self.inlined_get_root_key(id);
self.value(id).value.clone()
}
#[inline(always)]
pub fn inlined_probe_key_value<K1>(&mut self, id: K1) -> (K, V)
where
K1: Into<K>,
{
let id = id.into();
let id = self.inlined_get_root_key(id);
(id, self.value(id).value.clone())
}
}
impl UnifyValue for () {
type Error = NoError;
fn unify_values(_: &(), _: &()) -> Result<(), NoError> {
Ok(())
}
}
impl<V: UnifyValue> UnifyValue for Option<V> {
type Error = V::Error;
fn unify_values(a: &Option<V>, b: &Option<V>) -> Result<Self, V::Error> {
match (a, b) {
(&None, &None) => Ok(None),
(&Some(ref v), &None) | (&None, &Some(ref v)) => Ok(Some(v.clone())),
(&Some(ref a), &Some(ref b)) => match V::unify_values(a, b) {
Ok(v) => Ok(Some(v)),
Err(err) => Err(err),
},
}
}
}