blob: 481fd44d54589c5d523aff48eea267b8819d25de [file] [log] [blame]
// 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.
// Naming the benchmarks using uppercase letters helps them sort
// better.
#![allow(non_snake_case)]
#[cfg(feature = "bench")]
extern crate test;
#[cfg(feature = "bench")]
use self::test::Bencher;
use std::cmp;
use unify::{NoError, InPlace, InPlaceUnificationTable, UnifyKey, EqUnifyValue, UnifyValue};
use unify::{UnificationStore, UnificationTable};
#[cfg(feature = "persistent")]
use unify::Persistent;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct UnitKey(u32);
impl UnifyKey for UnitKey {
type Value = ();
fn index(&self) -> u32 {
self.0
}
fn from_index(u: u32) -> UnitKey {
UnitKey(u)
}
fn tag() -> &'static str {
"UnitKey"
}
}
macro_rules! all_modes {
($name:ident for $t:ty => $body:tt) => {
fn test_body<$name: UnificationStore<Key = $t, Value = <$t as UnifyKey>::Value>>() {
$body
}
test_body::<InPlace<$t>>();
#[cfg(feature = "persistent")]
test_body::<Persistent<$t>>();
}
}
#[test]
fn basic() {
all_modes! {
S for UnitKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(());
let k2 = ut.new_key(());
assert_eq!(ut.unioned(k1, k2), false);
ut.union(k1, k2);
assert_eq!(ut.unioned(k1, k2), true);
}
}
}
#[test]
fn big_array() {
all_modes! {
S for UnitKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
}
}
}
#[cfg(feature = "bench")]
fn big_array_bench_generic<S: UnificationStore<Key=UnitKey, Value=()>>(b: &mut Bencher) {
let mut ut: UnificationTable<S> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
b.iter(|| {
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
})
}
#[cfg(feature = "bench")]
#[bench]
fn big_array_bench_InPlace(b: &mut Bencher) {
big_array_bench_generic::<InPlace<UnitKey>>(b);
}
#[cfg(all(feature = "bench", feature = "persistent"))]
#[bench]
fn big_array_bench_Persistent(b: &mut Bencher) {
big_array_bench_generic::<Persistent<UnitKey>>(b);
}
#[cfg(feature = "bench")]
fn big_array_bench_in_snapshot_generic<S: UnificationStore<Key=UnitKey, Value=()>>(b: &mut Bencher) {
let mut ut: UnificationTable<S> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
b.iter(|| {
let snapshot = ut.snapshot();
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
ut.rollback_to(snapshot);
})
}
#[cfg(feature = "bench")]
#[bench]
fn big_array_bench_in_snapshot_InPlace(b: &mut Bencher) {
big_array_bench_in_snapshot_generic::<InPlace<UnitKey>>(b);
}
#[cfg(all(feature = "bench", feature = "persistent"))]
#[bench]
fn big_array_bench_in_snapshot_Persistent(b: &mut Bencher) {
big_array_bench_in_snapshot_generic::<Persistent<UnitKey>>(b);
}
#[cfg(feature = "bench")]
fn big_array_bench_clone_generic<S: UnificationStore<Key=UnitKey, Value=()>>(b: &mut Bencher) {
let mut ut: UnificationTable<S> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 15;
for _ in 0..MAX {
keys.push(ut.new_key(()));
}
b.iter(|| {
let saved_table = ut.clone();
for i in 1..MAX {
let l = keys[i - 1];
let r = keys[i];
ut.union(l, r);
}
for i in 0..MAX {
assert!(ut.unioned(keys[0], keys[i]));
}
ut = saved_table;
})
}
#[cfg(feature = "bench")]
#[bench]
fn big_array_bench_clone_InPlace(b: &mut Bencher) {
big_array_bench_clone_generic::<InPlace<UnitKey>>(b);
}
#[cfg(all(feature = "bench", feature = "persistent"))]
#[bench]
fn big_array_bench_clone_Persistent(b: &mut Bencher) {
big_array_bench_clone_generic::<Persistent<UnitKey>>(b);
}
#[test]
fn even_odd() {
all_modes! {
S for UnitKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let mut keys = Vec::new();
const MAX: usize = 1 << 10;
for i in 0..MAX {
let key = ut.new_key(());
keys.push(key);
if i >= 2 {
ut.union(key, keys[i - 2]);
}
}
for i in 1..MAX {
assert!(!ut.unioned(keys[i - 1], keys[i]));
}
for i in 2..MAX {
assert!(ut.unioned(keys[i - 2], keys[i]));
}
}
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct IntKey(u32);
impl UnifyKey for IntKey {
type Value = Option<i32>;
fn index(&self) -> u32 {
self.0
}
fn from_index(u: u32) -> IntKey {
IntKey(u)
}
fn tag() -> &'static str {
"IntKey"
}
}
impl EqUnifyValue for i32 {}
#[test]
fn unify_same_int_twice() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_value(k2, Some(22)).is_ok());
assert!(ut.unify_var_var(k1, k2).is_ok());
assert_eq!(ut.probe_value(k1), Some(22));
}
}
}
#[test]
fn unify_vars_then_int_indirect() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
assert!(ut.unify_var_var(k1, k2).is_ok());
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert_eq!(ut.probe_value(k2), Some(22));
}
}
}
#[test]
fn unify_vars_different_ints_1() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
assert!(ut.unify_var_var(k1, k2).is_ok());
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_value(k2, Some(23)).is_err());
}
}
}
#[test]
fn unify_vars_different_ints_2() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
assert!(ut.unify_var_var(k2, k1).is_ok());
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_value(k2, Some(23)).is_err());
}
}
}
#[test]
fn unify_distinct_ints_then_vars() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_value(k2, Some(23)).is_ok());
assert!(ut.unify_var_var(k2, k1).is_err());
}
}
}
#[test]
fn unify_root_value_1() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
let k3 = ut.new_key(None);
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_var(k1, k2).is_ok());
assert!(ut.unify_var_value(k3, Some(23)).is_ok());
assert!(ut.unify_var_var(k1, k3).is_err());
}
}
}
#[test]
fn unify_root_value_2() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
let k3 = ut.new_key(None);
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_var(k2, k1).is_ok());
assert!(ut.unify_var_value(k3, Some(23)).is_ok());
assert!(ut.unify_var_var(k1, k3).is_err());
}
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct OrderedKey(u32);
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct OrderedRank(u32);
impl UnifyKey for OrderedKey {
type Value = OrderedRank;
fn index(&self) -> u32 {
self.0
}
fn from_index(u: u32) -> OrderedKey {
OrderedKey(u)
}
fn tag() -> &'static str {
"OrderedKey"
}
fn order_roots(
a: OrderedKey,
a_rank: &OrderedRank,
b: OrderedKey,
b_rank: &OrderedRank,
) -> Option<(OrderedKey, OrderedKey)> {
println!("{:?} vs {:?}", a_rank, b_rank);
if a_rank > b_rank {
Some((a, b))
} else if b_rank > a_rank {
Some((b, a))
} else {
None
}
}
}
impl UnifyValue for OrderedRank {
type Error = NoError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
Ok(OrderedRank(cmp::max(value1.0, value2.0)))
}
}
#[test]
fn ordered_key() {
all_modes! {
S for OrderedKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k0_1 = ut.new_key(OrderedRank(0));
let k0_2 = ut.new_key(OrderedRank(0));
let k0_3 = ut.new_key(OrderedRank(0));
let k0_4 = ut.new_key(OrderedRank(0));
ut.union(k0_1, k0_2); // rank of one of those will now be 1
ut.union(k0_3, k0_4); // rank of new root also 1
ut.union(k0_1, k0_3); // rank of new root now 2
let k0_5 = ut.new_key(OrderedRank(0));
let k0_6 = ut.new_key(OrderedRank(0));
ut.union(k0_5, k0_6); // rank of new root now 1
ut.union(k0_1, k0_5); // new root rank 2, should not be k0_5 or k0_6
assert!(vec![k0_1, k0_2, k0_3, k0_4].contains(&ut.find(k0_1)));
}
}
}
#[test]
fn ordered_key_k1() {
all_modes! {
S for UnitKey => {
let mut ut: InPlaceUnificationTable<OrderedKey> = UnificationTable::new();
let k0_1 = ut.new_key(OrderedRank(0));
let k0_2 = ut.new_key(OrderedRank(0));
let k0_3 = ut.new_key(OrderedRank(0));
let k0_4 = ut.new_key(OrderedRank(0));
ut.union(k0_1, k0_2); // rank of one of those will now be 1
ut.union(k0_3, k0_4); // rank of new root also 1
ut.union(k0_1, k0_3); // rank of new root now 2
let k1_5 = ut.new_key(OrderedRank(1));
let k1_6 = ut.new_key(OrderedRank(1));
ut.union(k1_5, k1_6); // rank of new root now 1
ut.union(k0_1, k1_5); // even though k1 has lower rank, it wins
assert!(
vec![k1_5, k1_6].contains(&ut.find(k0_1)),
"unexpected choice for root: {:?}",
ut.find(k0_1)
);
}
}
}
/// Test that we *can* clone.
#[test]
fn clone_table() {
all_modes! {
S for IntKey => {
let mut ut: UnificationTable<S> = UnificationTable::new();
let k1 = ut.new_key(None);
let k2 = ut.new_key(None);
let k3 = ut.new_key(None);
assert!(ut.unify_var_value(k1, Some(22)).is_ok());
assert!(ut.unify_var_value(k2, Some(22)).is_ok());
assert!(ut.unify_var_var(k1, k2).is_ok());
assert_eq!(ut.probe_value(k3), None);
let mut ut1 = ut.clone();
assert_eq!(ut1.probe_value(k1), Some(22));
assert_eq!(ut1.probe_value(k3), None);
assert!(ut.unify_var_value(k3, Some(44)).is_ok());
assert_eq!(ut1.probe_value(k1), Some(22));
assert_eq!(ut1.probe_value(k3), None);
assert_eq!(ut.probe_value(k3), Some(44));
}
}
}