Remove ena

This commit is contained in:
Richard Feldman 2019-08-10 19:56:18 -04:00
parent f8c73a353b
commit 4df39b1afd
6 changed files with 0 additions and 1349 deletions

View file

@ -1,301 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// A very simple BitVector type.
pub struct BitVector {
data: Vec<u64>,
}
impl BitVector {
pub fn new(num_bits: usize) -> BitVector {
let num_words = u64s(num_bits);
BitVector { data: vec![0; num_words] }
}
pub fn contains(&self, bit: usize) -> bool {
let (word, mask) = word_mask(bit);
(self.data[word] & mask) != 0
}
/// Returns true if the bit has changed.
pub fn insert(&mut self, bit: usize) -> bool {
let (word, mask) = word_mask(bit);
let data = &mut self.data[word];
let value = *data;
let new_value = value | mask;
*data = new_value;
new_value != value
}
pub fn insert_all(&mut self, all: &BitVector) -> bool {
assert!(self.data.len() == all.data.len());
let mut changed = false;
for (i, j) in self.data.iter_mut().zip(&all.data) {
let value = *i;
*i = value | *j;
if value != *i {
changed = true;
}
}
changed
}
pub fn grow(&mut self, num_bits: usize) {
let num_words = u64s(num_bits);
let extra_words = self.data.len() - num_words;
self.data.extend((0..extra_words).map(|_| 0));
}
/// Iterates over indexes of set bits in a sorted order
pub fn iter<'a>(&'a self) -> BitVectorIter<'a> {
BitVectorIter {
iter: self.data.iter(),
current: 0,
idx: 0,
}
}
}
pub struct BitVectorIter<'a> {
iter: ::std::slice::Iter<'a, u64>,
current: u64,
idx: usize,
}
impl<'a> Iterator for BitVectorIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.current == 0 {
self.current = if let Some(&i) = self.iter.next() {
if i == 0 {
self.idx += 64;
continue;
} else {
self.idx = u64s(self.idx) * 64;
i
}
} else {
return None;
}
}
let offset = self.current.trailing_zeros() as usize;
self.current >>= offset;
self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000
self.idx += offset + 1;
return Some(self.idx - 1);
}
}
/// A "bit matrix" is basically a square matrix of booleans
/// represented as one gigantic bitvector. In other words, it is as if
/// you have N bitvectors, each of length N. Note that `elements` here is `N`/
#[derive(Clone)]
pub struct BitMatrix {
elements: usize,
vector: Vec<u64>,
}
impl BitMatrix {
// Create a new `elements x elements` matrix, initially empty.
pub fn new(elements: usize) -> BitMatrix {
// For every element, we need one bit for every other
// element. Round up to an even number of u64s.
let u64s_per_elem = u64s(elements);
BitMatrix {
elements: elements,
vector: vec![0; elements * u64s_per_elem],
}
}
/// The range of bits for a given element.
fn range(&self, element: usize) -> (usize, usize) {
let u64s_per_elem = u64s(self.elements);
let start = element * u64s_per_elem;
(start, start + u64s_per_elem)
}
pub fn add(&mut self, source: usize, target: usize) -> bool {
let (start, _) = self.range(source);
let (word, mask) = word_mask(target);
let mut vector = &mut self.vector[..];
let v1 = vector[start + word];
let v2 = v1 | mask;
vector[start + word] = v2;
v1 != v2
}
/// Do the bits from `source` contain `target`?
///
/// Put another way, if the matrix represents (transitive)
/// reachability, can `source` reach `target`?
pub fn contains(&self, source: usize, target: usize) -> bool {
let (start, _) = self.range(source);
let (word, mask) = word_mask(target);
(self.vector[start + word] & mask) != 0
}
/// Returns those indices that are reachable from both `a` and
/// `b`. This is an O(n) operation where `n` is the number of
/// elements (somewhat independent from the actual size of the
/// intersection, in particular).
pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> {
let (a_start, a_end) = self.range(a);
let (b_start, b_end) = self.range(b);
let mut result = Vec::with_capacity(self.elements);
for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
let mut v = self.vector[i] & self.vector[j];
for bit in 0..64 {
if v == 0 {
break;
}
if v & 0x1 != 0 {
result.push(base * 64 + bit);
}
v >>= 1;
}
}
result
}
/// Add the bits from `read` to the bits from `write`,
/// return true if anything changed.
///
/// This is used when computing transitive reachability because if
/// you have an edge `write -> read`, because in that case
/// `write` can reach everything that `read` can (and
/// potentially more).
pub fn merge(&mut self, read: usize, write: usize) -> bool {
let (read_start, read_end) = self.range(read);
let (write_start, write_end) = self.range(write);
let vector = &mut self.vector[..];
let mut changed = false;
for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
let v1 = vector[write_index];
let v2 = v1 | vector[read_index];
vector[write_index] = v2;
changed = changed | (v1 != v2);
}
changed
}
}
fn u64s(elements: usize) -> usize {
(elements + 63) / 64
}
fn word_mask(index: usize) -> (usize, u64) {
let word = index / 64;
let mask = 1 << (index % 64);
(word, mask)
}
#[test]
fn bitvec_iter_works() {
let mut bitvec = BitVector::new(100);
bitvec.insert(1);
bitvec.insert(10);
bitvec.insert(19);
bitvec.insert(62);
bitvec.insert(63);
bitvec.insert(64);
bitvec.insert(65);
bitvec.insert(66);
bitvec.insert(99);
assert_eq!(bitvec.iter().collect::<Vec<_>>(),
[1, 10, 19, 62, 63, 64, 65, 66, 99]);
}
#[test]
fn bitvec_iter_works_2() {
let mut bitvec = BitVector::new(300);
bitvec.insert(1);
bitvec.insert(10);
bitvec.insert(19);
bitvec.insert(62);
bitvec.insert(66);
bitvec.insert(99);
bitvec.insert(299);
assert_eq!(bitvec.iter().collect::<Vec<_>>(),
[1, 10, 19, 62, 66, 99, 299]);
}
#[test]
fn bitvec_iter_works_3() {
let mut bitvec = BitVector::new(319);
bitvec.insert(0);
bitvec.insert(127);
bitvec.insert(191);
bitvec.insert(255);
bitvec.insert(319);
assert_eq!(bitvec.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]);
}
#[test]
fn union_two_vecs() {
let mut vec1 = BitVector::new(65);
let mut vec2 = BitVector::new(65);
assert!(vec1.insert(3));
assert!(!vec1.insert(3));
assert!(vec2.insert(5));
assert!(vec2.insert(64));
assert!(vec1.insert_all(&vec2));
assert!(!vec1.insert_all(&vec2));
assert!(vec1.contains(3));
assert!(!vec1.contains(4));
assert!(vec1.contains(5));
assert!(!vec1.contains(63));
assert!(vec1.contains(64));
}
#[test]
fn grow() {
let mut vec1 = BitVector::new(65);
assert!(vec1.insert(3));
assert!(!vec1.insert(3));
assert!(vec1.insert(5));
assert!(vec1.insert(64));
vec1.grow(128);
assert!(vec1.contains(3));
assert!(vec1.contains(5));
assert!(vec1.contains(64));
assert!(!vec1.contains(126));
}
#[test]
fn matrix_intersection() {
let mut vec1 = BitMatrix::new(200);
// (*) Elements reachable from both 2 and 65.
vec1.add(2, 3);
vec1.add(2, 6);
vec1.add(2, 10); // (*)
vec1.add(2, 64); // (*)
vec1.add(2, 65);
vec1.add(2, 130);
vec1.add(2, 160); // (*)
vec1.add(64, 133);
vec1.add(65, 2);
vec1.add(65, 8);
vec1.add(65, 10); // (*)
vec1.add(65, 64); // (*)
vec1.add(65, 68);
vec1.add(65, 133);
vec1.add(65, 160); // (*)
let intersection = vec1.intersection(2, 64);
assert!(intersection.is_empty());
let intersection = vec1.intersection(2, 65);
assert_eq!(intersection, &[10, 64, 160]);
}

View file

@ -1,15 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! An implementation of union-find. See the `unify` module for more
//! details.
pub mod snapshot_vec;
pub mod unify;

View file

@ -1,370 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits
//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either
//! to rollback to the start of the snapshot or commit those changes.
//!
//! This vector is intended to be used as part of an abstraction, not serve as a complete
//! abstraction on its own. As such, while it will roll back most changes on its own, it also
//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To
//! ensure that any changes you make this with this pointer are rolled back, you must invoke
//! `record` to record any changes you make and also supplying a delegate capable of reversing
//! those changes.
use self::UndoLog::*;
use std::fmt;
use std::mem;
use std::ops;
#[derive(Debug)]
pub enum UndoLog<D: SnapshotVecDelegate> {
/// New variable with given index was created.
NewElem(usize),
/// Variable with given index was changed *from* the given value.
SetElem(usize, D::Value),
/// Extensible set of actions
Other(D::Undo),
}
pub struct SnapshotVec<D: SnapshotVecDelegate> {
values: Vec<D::Value>,
undo_log: Vec<UndoLog<D>>,
num_open_snapshots: usize,
}
impl<D> fmt::Debug for SnapshotVec<D>
where D: SnapshotVecDelegate,
D: fmt::Debug,
D::Undo: fmt::Debug,
D::Value: fmt::Debug
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SnapshotVec")
.field("values", &self.values)
.field("undo_log", &self.undo_log)
.field("num_open_snapshots", &self.num_open_snapshots)
.finish()
}
}
// Snapshots are tokens that should be created/consumed linearly.
pub struct Snapshot {
// Length of the undo log at the time the snapshot was taken.
length: usize,
}
pub trait SnapshotVecDelegate {
type Value;
type Undo;
fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo);
}
// HACK(eddyb) manual impl avoids `Default` bound on `D`.
impl<D: SnapshotVecDelegate> Default for SnapshotVec<D> {
fn default() -> Self {
SnapshotVec {
values: Vec::new(),
undo_log: Vec::new(),
num_open_snapshots: 0,
}
}
}
impl<D: SnapshotVecDelegate> SnapshotVec<D> {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(c: usize) -> SnapshotVec<D> {
SnapshotVec {
values: Vec::with_capacity(c),
undo_log: Vec::new(),
num_open_snapshots: 0,
}
}
fn in_snapshot(&self) -> bool {
self.num_open_snapshots > 0
}
pub fn record(&mut self, action: D::Undo) {
if self.in_snapshot() {
self.undo_log.push(Other(action));
}
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn push(&mut self, elem: D::Value) -> usize {
let len = self.values.len();
self.values.push(elem);
if self.in_snapshot() {
self.undo_log.push(NewElem(len));
}
len
}
pub fn get(&self, index: usize) -> &D::Value {
&self.values[index]
}
/// Reserve space for new values, just like an ordinary vec.
pub fn reserve(&mut self, additional: usize) {
// This is not affected by snapshots or anything.
self.values.reserve(additional);
}
/// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone
/// automatically, so you should be sure call `record()` with some sort of suitable undo
/// action.
pub fn get_mut(&mut self, index: usize) -> &mut D::Value {
&mut self.values[index]
}
/// Updates the element at the given index. The old value will saved (and perhaps restored) if
/// a snapshot is active.
pub fn set(&mut self, index: usize, new_elem: D::Value) {
let old_elem = mem::replace(&mut self.values[index], new_elem);
if self.in_snapshot() {
self.undo_log.push(SetElem(index, old_elem));
}
}
/// Updates all elements. Potentially more efficient -- but
/// otherwise equivalent to -- invoking `set` for each element.
pub fn set_all(&mut self, mut new_elems: impl FnMut(usize) -> D::Value) {
if !self.in_snapshot() {
for (slot, index) in self.values.iter_mut().zip(0..) {
*slot = new_elems(index);
}
} else {
for i in 0..self.values.len() {
self.set(i, new_elems(i));
}
}
}
pub fn update<OP>(&mut self, index: usize, op: OP)
where
OP: FnOnce(&mut D::Value),
D::Value: Clone,
{
if self.in_snapshot() {
let old_elem = self.values[index].clone();
self.undo_log.push(SetElem(index, old_elem));
}
op(&mut self.values[index]);
}
pub fn start_snapshot(&mut self) -> Snapshot {
let length = self.undo_log.len();
self.num_open_snapshots += 1;
Snapshot { length: length }
}
pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] {
&self.undo_log[snapshot.length..]
}
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
// Failures here may indicate a failure to follow a stack discipline.
assert!(self.undo_log.len() >= snapshot.length);
assert!(self.num_open_snapshots > 0);
}
pub fn rollback_to(&mut self, snapshot: Snapshot) {
debug!("rollback_to({})", snapshot.length);
self.assert_open_snapshot(&snapshot);
while self.undo_log.len() > snapshot.length {
match self.undo_log.pop().unwrap() {
NewElem(i) => {
self.values.pop();
assert!(self.values.len() == i);
}
SetElem(i, v) => {
self.values[i] = v;
}
Other(u) => {
D::reverse(&mut self.values, u);
}
}
}
self.num_open_snapshots -= 1;
}
/// Commits all changes since the last snapshot. Of course, they
/// can still be undone if there is a snapshot further out.
pub fn commit(&mut self, snapshot: Snapshot) {
debug!("commit({})", snapshot.length);
self.assert_open_snapshot(&snapshot);
if self.num_open_snapshots == 1 {
// The root snapshot. It's safe to clear the undo log because
// there's no snapshot further out that we might need to roll back
// to.
assert!(snapshot.length == 0);
self.undo_log.clear();
}
self.num_open_snapshots -= 1;
}
}
impl<D: SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
type Target = [D::Value];
fn deref(&self) -> &[D::Value] {
&*self.values
}
}
impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
fn deref_mut(&mut self) -> &mut [D::Value] {
&mut *self.values
}
}
impl<D: SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
type Output = D::Value;
fn index(&self, index: usize) -> &D::Value {
self.get(index)
}
}
impl<D: SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
fn index_mut(&mut self, index: usize) -> &mut D::Value {
self.get_mut(index)
}
}
impl<D: SnapshotVecDelegate> Extend<D::Value> for SnapshotVec<D> {
fn extend<T>(&mut self, iterable: T)
where
T: IntoIterator<Item = D::Value>,
{
let initial_len = self.values.len();
self.values.extend(iterable);
let final_len = self.values.len();
if self.in_snapshot() {
self.undo_log.extend((initial_len..final_len).map(|len| NewElem(len)));
}
}
}
impl<D: SnapshotVecDelegate> Clone for SnapshotVec<D>
where
D::Value: Clone,
D::Undo: Clone,
{
fn clone(&self) -> Self {
SnapshotVec {
values: self.values.clone(),
undo_log: self.undo_log.clone(),
num_open_snapshots: self.num_open_snapshots,
}
}
}
impl<D: SnapshotVecDelegate> Clone for UndoLog<D>
where
D::Value: Clone,
D::Undo: Clone,
{
fn clone(&self) -> Self {
match *self {
NewElem(i) => NewElem(i),
SetElem(i, ref v) => SetElem(i, v.clone()),
Other(ref u) => Other(u.clone()),
}
}
}
impl SnapshotVecDelegate for i32 {
type Value = i32;
type Undo = ();
fn reverse(_: &mut Vec<i32>, _: ()) {}
}
#[test]
fn basic() {
let mut vec: SnapshotVec<i32> = SnapshotVec::default();
assert!(!vec.in_snapshot());
assert_eq!(vec.len(), 0);
vec.push(22);
vec.push(33);
assert_eq!(vec.len(), 2);
assert_eq!(*vec.get(0), 22);
assert_eq!(*vec.get(1), 33);
vec.set(1, 34);
assert_eq!(vec.len(), 2);
assert_eq!(*vec.get(0), 22);
assert_eq!(*vec.get(1), 34);
let snapshot = vec.start_snapshot();
assert!(vec.in_snapshot());
vec.push(44);
vec.push(55);
vec.set(1, 35);
assert_eq!(vec.len(), 4);
assert_eq!(*vec.get(0), 22);
assert_eq!(*vec.get(1), 35);
assert_eq!(*vec.get(2), 44);
assert_eq!(*vec.get(3), 55);
vec.rollback_to(snapshot);
assert!(!vec.in_snapshot());
assert_eq!(vec.len(), 2);
assert_eq!(*vec.get(0), 22);
assert_eq!(*vec.get(1), 34);
}
#[test]
#[should_panic]
fn out_of_order() {
let mut vec: SnapshotVec<i32> = SnapshotVec::default();
vec.push(22);
let snapshot1 = vec.start_snapshot();
vec.push(33);
let snapshot2 = vec.start_snapshot();
vec.push(44);
vec.rollback_to(snapshot1); // bogus, but accepted
vec.rollback_to(snapshot2); // asserts
}
#[test]
fn nested_commit_then_rollback() {
let mut vec: SnapshotVec<i32> = SnapshotVec::default();
vec.push(22);
let snapshot1 = vec.start_snapshot();
let snapshot2 = vec.start_snapshot();
vec.set(0, 23);
vec.commit(snapshot2);
assert_eq!(*vec.get(0), 23);
vec.rollback_to(snapshot1);
assert_eq!(*vec.get(0), 22);
}

View file

@ -1,214 +0,0 @@
// This is a fork of ena, whose copyright and license info is in ena/unify/mod.rs
#[cfg(feature = "persistent")]
use dogged::DVec;
use ena::snapshot_vec as sv;
use std::ops;
use std::marker::PhantomData;
use std::fmt::Debug;
use super::{VarValue, UnifyKey};
#[allow(dead_code)] // rustc BUG
#[allow(type_alias_bounds)]
type Key<S: UnificationStore> = <S as UnificationStore>::Key;
/// Largely internal trait implemented by the unification table
/// backing store types. The most common such type is `InPlace`,
/// which indicates a standard, mutable unification table.
pub trait UnificationStore:
ops::Index<usize, Output = VarValue<Key<Self>>> + Clone + Default
{
type Key: UnifyKey<Value = Self::Value>;
type Value: Debug + Clone;
type Snapshot;
fn start_snapshot(&mut self) -> Self::Snapshot;
fn rollback_to(&mut self, snapshot: Self::Snapshot);
fn commit(&mut self, snapshot: Self::Snapshot);
fn reset_unifications(
&mut self,
value: impl FnMut(u32) -> VarValue<Self::Key>,
);
fn len(&self) -> usize;
fn push(&mut self, value: VarValue<Self::Key>);
fn reserve(&mut self, num_new_values: usize);
fn update<F>(&mut self, index: usize, op: F)
where F: FnOnce(&mut VarValue<Self::Key>);
fn tag() -> &'static str {
Self::Key::tag()
}
}
/// Backing store for an in-place unification table.
/// Not typically used directly.
#[derive(Clone, Debug)]
pub struct InPlace<K: UnifyKey> {
values: sv::SnapshotVec<Delegate<K>>
}
// HACK(eddyb) manual impl avoids `Default` bound on `K`.
impl<K: UnifyKey> Default for InPlace<K> {
fn default() -> Self {
InPlace { values: sv::SnapshotVec::new() }
}
}
impl<K: UnifyKey> UnificationStore for InPlace<K> {
type Key = K;
type Value = K::Value;
type Snapshot = sv::Snapshot;
#[inline]
fn start_snapshot(&mut self) -> Self::Snapshot {
self.values.start_snapshot()
}
#[inline]
fn rollback_to(&mut self, snapshot: Self::Snapshot) {
self.values.rollback_to(snapshot);
}
#[inline]
fn commit(&mut self, snapshot: Self::Snapshot) {
self.values.commit(snapshot);
}
#[inline]
fn reset_unifications(
&mut self,
mut value: impl FnMut(u32) -> VarValue<Self::Key>,
) {
self.values.set_all(|i| value(i as u32));
}
#[inline]
fn len(&self) -> usize {
self.values.len()
}
#[inline]
fn push(&mut self, value: VarValue<Self::Key>) {
self.values.push(value);
}
#[inline]
fn reserve(&mut self, num_new_values: usize) {
self.values.reserve(num_new_values);
}
#[inline]
fn update<F>(&mut self, index: usize, op: F)
where F: FnOnce(&mut VarValue<Self::Key>)
{
self.values.update(index, op)
}
}
impl<K> ops::Index<usize> for InPlace<K>
where K: UnifyKey
{
type Output = VarValue<K>;
fn index(&self, index: usize) -> &VarValue<K> {
&self.values[index]
}
}
#[derive(Copy, Clone, Debug)]
struct Delegate<K>(PhantomData<K>);
impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
type Value = VarValue<K>;
type Undo = ();
fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
}
#[cfg(feature = "persistent")]
#[derive(Clone, Debug)]
pub struct Persistent<K: UnifyKey> {
values: DVec<VarValue<K>>
}
// HACK(eddyb) manual impl avoids `Default` bound on `K`.
#[cfg(feature = "persistent")]
impl<K: UnifyKey> Default for Persistent<K> {
fn default() -> Self {
Persistent { values: DVec::new() }
}
}
#[cfg(feature = "persistent")]
impl<K: UnifyKey> UnificationStore for Persistent<K> {
type Key = K;
type Value = K::Value;
type Snapshot = Self;
#[inline]
fn start_snapshot(&mut self) -> Self::Snapshot {
self.clone()
}
#[inline]
fn rollback_to(&mut self, snapshot: Self::Snapshot) {
*self = snapshot;
}
#[inline]
fn commit(&mut self, _snapshot: Self::Snapshot) {
}
#[inline]
fn reset_unifications(
&mut self,
mut value: impl FnMut(u32) -> VarValue<Self::Key>,
) {
// Without extending dogged, there isn't obviously a more
// efficient way to do this. But it's pretty dumb. Maybe
// dogged needs a `map`.
for i in 0 .. self.values.len() {
self.values[i] = value(i as u32);
}
}
#[inline]
fn len(&self) -> usize {
self.values.len()
}
#[inline]
fn push(&mut self, value: VarValue<Self::Key>) {
self.values.push(value);
}
#[inline]
fn reserve(&mut self, _num_new_values: usize) {
// not obviously relevant to DVec.
}
#[inline]
fn update<F>(&mut self, index: usize, op: F)
where F: FnOnce(&mut VarValue<Self::Key>)
{
let p = &mut self.values[index];
op(p);
}
}
#[cfg(feature = "persistent")]
impl<K> ops::Index<usize> for Persistent<K>
where K: UnifyKey
{
type Output = VarValue<K>;
fn index(&self, index: usize) -> &VarValue<K> {
&self.values[index]
}
}

View file

@ -1,444 +0,0 @@
// This is a fork of ena, whose copyright and license info is below.
//
// The fork was made primarily in order to support unifying type unions, which
// requires looking up the current values of keys in the middle of unification.
// This fork implements that by replacing the UnificationValue trait with
// FnOnce callbacks which accept the table as well as the values to unify.
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Union-find implementation. The main type is `UnificationTable`.
//!
//! You can define your own type for the *keys* in the table, but you
//! must implement `UnifyKey` for that type. The assumption is that
//! keys will be newtyped integers, hence we require that they
//! implement `Copy`.
//!
//! Keys can have values associated with them. The assumption is that
//! these values are cheaply cloneable (ideally, `Copy`), and some of
//! the interfaces are oriented around that assumption. If you just
//! want the classical "union-find" algorithm where you group things
//! into sets, use the `Value` type of `()`.
//!
//! When you have keys with non-trivial values, you must also define
//! how those values can be merged.
//!
//! The best way to see how it is used is to read the `tests.rs` file;
//! search for e.g. `UnitKey`.
use std::marker;
use std::fmt::Debug;
mod backing_vec;
pub use self::backing_vec::{InPlace, UnificationStore};
#[cfg(feature = "persistent")]
pub use self::backing_vec::Persistent;
#[cfg(test)]
mod tests;
/// This trait is implemented by any type that can serve as a type
/// variable. We call such variables *unification keys*. For example,
/// this trait is implemented by `IntVid`, which represents integral
/// variables.
///
/// Each key type has an associated value type `V`. For example, for
/// `IntVid`, this is `Option<IntVarValue>`, representing some
/// (possibly not yet known) sort of integer.
///
/// Clients are expected to provide implementations of this trait; you
/// can see some examples in the `test` module.
pub trait UnifyKey: Copy + Clone + Debug + PartialEq {
type Value: Clone + Debug;
fn index(&self) -> u32;
fn from_index(u: u32) -> Self;
fn tag() -> &'static str;
/// If true, then `self` should be preferred as root to `other`.
/// Note that we assume a consistent partial ordering, so
/// returning true implies that `other.prefer_as_root_to(self)`
/// would return false. If there is no ordering between two keys
/// (i.e., `a.prefer_as_root_to(b)` and `b.prefer_as_root_to(a)`
/// both return false) then the rank will be used to determine the
/// root in an optimal way.
///
/// NB. The only reason to implement this method is if you want to
/// control what value is returned from `find()`. In general, it
/// is better to let the unification table determine the root,
/// since overriding the rank can cause execution time to increase
/// dramatically.
#[allow(unused_variables)]
fn order_roots(
a: Self,
a_value: &Self::Value,
b: Self,
b_value: &Self::Value,
) -> Option<(Self, Self)> {
None
}
}
/// Value of a unification key. We implement Tarjan's union-find
/// algorithm: when two keys are unified, one of them is converted
/// into a "redirect" pointing at the other. These redirects form a
/// DAG: the roots of the DAG (nodes that are not redirected) are each
/// associated with a value of type `V` and a rank. The rank is used
/// to keep the DAG relatively balanced, which helps keep the running
/// time of the algorithm under control. For more information, see
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
#[derive(PartialEq, Clone, Debug)]
pub struct VarValue<K: UnifyKey> { // FIXME pub
parent: K, // if equal to self, this is a root
value: K::Value, // value assigned (only relevant to root)
rank: u32, // max depth (only relevant to root)
}
/// Table of unification keys and their values. You must define a key type K
/// that implements the `UnifyKey` trait. Unification tables can be used in two-modes:
///
/// - in-place (`UnificationTable<InPlace<K>>` or `InPlaceUnificationTable<K>`):
/// - This is the standard mutable mode, where the array is modified
/// in place.
/// - To do backtracking, you can employ the `snapshot` and `rollback_to`
/// methods.
/// - persistent (`UnificationTable<Persistent<K>>` or `PersistentUnificationTable<K>`):
/// - In this mode, we use a persistent vector to store the data, so that
/// cloning the table is an O(1) operation.
/// - This implies that ordinary operations are quite a bit slower though.
/// - Requires the `persistent` feature be selected in your Cargo.toml file.
#[derive(Clone, Debug, Default)]
pub struct UnificationTable<S: UnificationStore> {
/// Indicates the current value of each key.
values: S,
}
/// A unification table that uses an "in-place" vector.
#[allow(type_alias_bounds)]
pub type InPlaceUnificationTable<K: UnifyKey> = UnificationTable<InPlace<K>>;
/// A unification table that uses a "persistent" vector.
#[cfg(feature = "persistent")]
#[allow(type_alias_bounds)]
pub type PersistentUnificationTable<K: UnifyKey> = UnificationTable<Persistent<K>>;
/// At any time, users may snapshot a unification table. The changes
/// made during the snapshot may either be *committed* or *rolled back*.
pub struct Snapshot<S: UnificationStore> {
// Link snapshot to the unification store `S` of the table.
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, // this is a root
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;
}
fn parent(&self, self_key: K) -> Option<K> {
self.if_not_self(self.parent, self_key)
}
fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
if key == self_key {
None
} else {
Some(key)
}
}
}
// We can't use V:LatticeValue, much as I would like to,
// because frequently the pattern is that V=Option<U> for some
// other type parameter U, and we have no way to say
// Option<U>:LatticeValue.
impl<S: UnificationStore> UnificationTable<S> {
pub fn new() -> Self {
Self::default()
}
/// Starts a new snapshot. Each snapshot must be either
/// rolled back or committed in a "LIFO" (stack) order.
pub fn snapshot(&mut self) -> Snapshot<S> {
Snapshot {
marker: marker::PhantomData::<S>,
snapshot: self.values.start_snapshot(),
}
}
/// Reverses all changes since the last snapshot. Also
/// removes any keys that have been created since then.
pub fn rollback_to(&mut self, snapshot: Snapshot<S>) {
debug!("{}: rollback_to()", S::tag());
self.values.rollback_to(snapshot.snapshot);
}
/// Commits all changes since the last snapshot. Of course, they
/// can still be undone if there is a snapshot further out.
pub fn commit(&mut self, snapshot: Snapshot<S>) {
debug!("{}: commit()", S::tag());
self.values.commit(snapshot.snapshot);
}
/// Creates a fresh key with the given value.
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
}
/// Reserve memory for `num_new_keys` to be created. Does not
/// actually create the new keys; you must then invoke `new_key`.
pub fn reserve(&mut self, num_new_keys: usize) {
self.values.reserve(num_new_keys);
}
/// Clears all unifications that have been performed, resetting to
/// the initial state. The values of each variable are given by
/// the closure.
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)
});
}
/// Returns the number of keys created so far.
pub fn len(&self) -> usize {
self.values.len()
}
/// Obtains the current value for a particular key.
/// Not for end-users; they can use `probe_value`.
fn value(&self, key: S::Key) -> &VarValue<S::Key> {
&self.values[key.index() as usize]
}
/// Find the root node for `vid`. This uses the standard
/// union-find algorithm with path compression:
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
///
/// NB. This is a building-block operation and you would probably
/// prefer to call `probe` below.
fn get_root_key(&mut self, vid: S::Key) -> S::Key {
let redirect = {
match self.value(vid).parent(vid) {
None => return vid,
Some(redirect) => redirect,
}
};
let root_key: S::Key = self.get_root_key(redirect);
if root_key != redirect {
// Path compression
self.update_value(vid, |value| value.parent = root_key);
}
root_key
}
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));
}
/// Either redirects `node_a` to `node_b` or vice versa, depending
/// on the relative rank. The value associated with the new root
/// will be `new_value`.
///
/// NB: This is the "union" operation of "union-find". It is
/// really more of a building block. If the values associated with
/// your key are non-trivial, you would probably prefer to call
/// `unify_var_var` below.
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,
) {
// compute the new rank for the new root that they chose;
// this may not be the optimal choice.
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 {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
self.redirect_root(rank_a, key_b, key_a, new_value);
} else if rank_a < rank_b {
// b has greater rank, so a should redirect to b.
self.redirect_root(rank_b, key_a, key_b, new_value);
} else {
// If equal, redirect one to the other and increment the
// other's rank.
self.redirect_root(rank_a + 1, key_a, key_b, new_value);
}
}
/// Internal method to redirect `old_root_key` (which is currently
/// a root) to a child of `new_root_key` (which will remain a
/// root). The rank and value of `new_root_key` will be updated to
/// `new_rank` and `new_value` respectively.
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);
});
}
}
/// ////////////////////////////////////////////////////////////////////////
/// Public API
impl<'tcx, S, K, V> UnificationTable<S>
where
S: UnificationStore<Key = K, Value = V>,
K: UnifyKey<Value = V>,
V: Debug + Clone,
{
/// Unions two keys without the possibility of failure; only
/// applicable when unify values use `NoError` as their error
/// type.
pub fn union<K1, K2, F>(&mut self, a_id: K1, b_id: K2, unify_values: F)
where
K1: Into<K>,
K2: Into<K>,
V: Debug + Clone,
F: FnOnce(&Self, &V, &V) -> V
{
let a_id = a_id.into();
let b_id = b_id.into();
let root_a = self.get_root_key(a_id);
let root_b = self.get_root_key(b_id);
if root_a == root_b {
return;
}
let combined = unify_values(&self, &self.value(root_a).value, &self.value(root_b).value);
self.unify_roots(root_a, root_b, combined);
}
/// Unions a key and a value without the possibility of failure.
pub fn union_value<K1, F>(&mut self, id: K1, value: V, unify_values: F)
where
K1: Into<K>,
V: Debug + Clone,
F: FnOnce(&Self, &V, &V) -> V
{
self.unify_var_value(id, value, unify_values);
}
/// Given two keys, indicates whether they have been unioned together.
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)
}
/// Given a key, returns the (current) root key.
pub fn find<K1>(&mut self, id: K1) -> K
where
K1: Into<K>,
{
let id = id.into();
self.get_root_key(id)
}
/// Sets the value of the key `a_id` to `b`, attempting to merge
/// with the previous value.
pub fn unify_var_value<K1, F>(&mut self, a_id: K1, b: V, unify_values: F)
where
K1: Into<K>,
F: FnOnce(&Self, &V, &V) -> V
{
let a_id = a_id.into();
let root_a = self.get_root_key(a_id);
let value = unify_values(&self, &self.value(root_a).value, &b);
self.update_value(root_a, |node| node.value = value);
}
/// Returns the current value for the given key. If the key has
/// been union'd, this will give the value from the current root.
pub fn probe_value<K1>(&mut self, id: K1) -> V
where
K1: Into<K>,
{
let id = id.into();
let id = self.get_root_key(id);
self.value(id).value.clone()
}
}

View file

@ -8,11 +8,6 @@ pub mod canonicalize;
pub mod collections; pub mod collections;
pub mod graph; pub mod graph;
// #[macro_use]
// extern crate log;
#[cfg(feature = "persistent")]
extern crate dogged;
extern crate im_rc; extern crate im_rc;
extern crate fraction; extern crate fraction;