mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
remove ena dependency
This commit is contained in:
parent
d8196c7837
commit
0022f345ac
12 changed files with 0 additions and 1733 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -4140,7 +4140,6 @@ dependencies = [
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"static_assertions 1.1.0",
|
"static_assertions 1.1.0",
|
||||||
"ven_ena",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5076,13 +5075,6 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ven_ena"
|
|
||||||
version = "0.13.1"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ven_graph"
|
name = "ven_graph"
|
||||||
version = "2.0.5-pre"
|
version = "2.0.5-pre"
|
||||||
|
|
|
@ -27,7 +27,6 @@ members = [
|
||||||
"compiler/test_gen",
|
"compiler/test_gen",
|
||||||
"compiler/roc_target",
|
"compiler/roc_target",
|
||||||
"compiler/debug_flags",
|
"compiler/debug_flags",
|
||||||
"vendor/ena",
|
|
||||||
"vendor/inkwell",
|
"vendor/inkwell",
|
||||||
"vendor/pathfinding",
|
"vendor/pathfinding",
|
||||||
"vendor/pretty",
|
"vendor/pretty",
|
||||||
|
|
|
@ -11,6 +11,5 @@ roc_region = { path = "../region" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_error_macros = {path="../../error_macros"}
|
roc_error_macros = {path="../../error_macros"}
|
||||||
roc_debug_flags = {path="../debug_flags"}
|
roc_debug_flags = {path="../debug_flags"}
|
||||||
ven_ena = { path = "../../vendor/ena" }
|
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
|
|
|
@ -8,7 +8,6 @@ use roc_module::ident::{Lowercase, TagName, Uppercase};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::{once, Iterator, Map};
|
use std::iter::{once, Iterator, Map};
|
||||||
use ven_ena::unify::UnifyKey;
|
|
||||||
|
|
||||||
use crate::unification_table::{Snapshot, UnificationTable};
|
use crate::unification_table::{Snapshot, UnificationTable};
|
||||||
|
|
||||||
|
@ -1178,22 +1177,6 @@ impl fmt::Debug for Variable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnifyKey for Variable {
|
|
||||||
type Value = Descriptor;
|
|
||||||
|
|
||||||
fn index(&self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_index(index: u32) -> Self {
|
|
||||||
Variable(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tag() -> &'static str {
|
|
||||||
"Variable"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct LambdaSet(pub Variable);
|
pub struct LambdaSet(pub Variable);
|
||||||
|
|
||||||
|
|
13
vendor/ena/Cargo.toml
vendored
13
vendor/ena/Cargo.toml
vendored
|
@ -1,13 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "ven_ena"
|
|
||||||
description = "Union-find, congruence closure, and other unification code. Based on code from rustc."
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
homepage = "https://github.com/rust-lang-nursery/ena"
|
|
||||||
repository = "https://github.com/rust-lang-nursery/ena"
|
|
||||||
version = "0.13.1"
|
|
||||||
authors = ["Niko Matsakis <niko@alum.mit.edu>"]
|
|
||||||
readme = "README.md"
|
|
||||||
keywords = ["unification", "union-find"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
log = "0.4.14"
|
|
201
vendor/ena/LICENSE-APACHE
vendored
201
vendor/ena/LICENSE-APACHE
vendored
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
25
vendor/ena/LICENSE-MIT
vendored
25
vendor/ena/LICENSE-MIT
vendored
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2010 The Rust Project Developers
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
|
||||||
person obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without
|
|
||||||
limitation the rights to use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
|
||||||
shall be included in all copies or substantial portions
|
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
301
vendor/ena/src/bitvec.rs
vendored
301
vendor/ena/src/bitvec.rs
vendored
|
@ -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]);
|
|
||||||
}
|
|
18
vendor/ena/src/lib.rs
vendored
18
vendor/ena/src/lib.rs
vendored
|
@ -1,18 +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;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
399
vendor/ena/src/snapshot_vec.rs
vendored
399
vendor/ena/src/snapshot_vec.rs
vendored
|
@ -1,399 +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),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Vec where we have Debug overridden to render the indices like
|
|
||||||
/// a hashmap, since we really care about those when debugging one of these.
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct BackingVec<T>(Vec<T>);
|
|
||||||
|
|
||||||
pub struct SnapshotVec<D: SnapshotVecDelegate> {
|
|
||||||
values: BackingVec<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 {
|
|
||||||
self.values.fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshots are tokens that should be created/consumed linearly.
|
|
||||||
pub struct Snapshot {
|
|
||||||
// Number of values at the time the snapshot was taken.
|
|
||||||
pub(crate) value_count: usize,
|
|
||||||
// Length of the undo log at the time the snapshot was taken.
|
|
||||||
undo_len: 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: BackingVec(Vec::new()),
|
|
||||||
undo_log: Vec::new(),
|
|
||||||
num_open_snapshots: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> fmt::Debug for BackingVec<T>
|
|
||||||
where
|
|
||||||
T: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{{{{")?;
|
|
||||||
|
|
||||||
for (index, elem) in self.0.iter().enumerate() {
|
|
||||||
write!(f, "\n {} => {:?},", index, elem)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.0.is_empty() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(f, "}}}}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SnapshotVecDelegate> SnapshotVec<D> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_capacity(c: usize) -> SnapshotVec<D> {
|
|
||||||
SnapshotVec {
|
|
||||||
values: BackingVec(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.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.values.0.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, elem: D::Value) -> usize {
|
|
||||||
let len = self.values.0.len();
|
|
||||||
self.values.0.push(elem);
|
|
||||||
|
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(NewElem(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> &D::Value {
|
|
||||||
&self.values.0[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.0.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.0[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.0[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 (index, slot) in self.values.0.iter_mut().enumerate() {
|
|
||||||
*slot = new_elems(index);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 0..self.values.0.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.0[index].clone();
|
|
||||||
self.undo_log.push(SetElem(index, old_elem));
|
|
||||||
}
|
|
||||||
op(&mut self.values.0[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_snapshot(&mut self) -> Snapshot {
|
|
||||||
self.num_open_snapshots += 1;
|
|
||||||
Snapshot {
|
|
||||||
value_count: self.values.0.len(),
|
|
||||||
undo_len: self.undo_log.len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] {
|
|
||||||
&self.undo_log[snapshot.undo_len..]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
|
|
||||||
// Failures here may indicate a failure to follow a stack discipline.
|
|
||||||
assert!(self.undo_log.len() >= snapshot.undo_len);
|
|
||||||
assert!(self.num_open_snapshots > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback_to(&mut self, snapshot: Snapshot) {
|
|
||||||
debug!("rollback_to({})", snapshot.undo_len);
|
|
||||||
|
|
||||||
self.assert_open_snapshot(&snapshot);
|
|
||||||
|
|
||||||
while self.undo_log.len() > snapshot.undo_len {
|
|
||||||
match self.undo_log.pop().unwrap() {
|
|
||||||
NewElem(i) => {
|
|
||||||
self.values.0.pop();
|
|
||||||
assert!(self.values.0.len() == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetElem(i, v) => {
|
|
||||||
self.values.0[i] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
Other(u) => {
|
|
||||||
D::reverse(&mut self.values.0, 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.undo_len);
|
|
||||||
|
|
||||||
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.undo_len == 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.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
|
|
||||||
fn deref_mut(&mut self) -> &mut [D::Value] {
|
|
||||||
&mut *self.values.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.0.len();
|
|
||||||
self.values.0.extend(iterable);
|
|
||||||
let final_len = self.values.0.len();
|
|
||||||
|
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.extend((initial_len..final_len).map(NewElem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
249
vendor/ena/src/unify/backing_vec.rs
vendored
249
vendor/ena/src/unify/backing_vec.rs
vendored
|
@ -1,249 +0,0 @@
|
||||||
use crate::snapshot_vec as sv;
|
|
||||||
#[cfg(feature = "persistent")]
|
|
||||||
use im_rc::Vector;
|
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::ops::{self, Range};
|
|
||||||
|
|
||||||
use super::{UnifyKey, VarValue};
|
|
||||||
|
|
||||||
#[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>>>
|
|
||||||
+ ops::IndexMut<usize, Output = VarValue<Key<Self>>>
|
|
||||||
+ Clone
|
|
||||||
+ Default
|
|
||||||
{
|
|
||||||
type Key: UnifyKey<Value = Self::Value>;
|
|
||||||
type Value: Clone + Debug;
|
|
||||||
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 values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range<usize>;
|
|
||||||
|
|
||||||
fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue<Self::Key>);
|
|
||||||
|
|
||||||
fn len(&self) -> usize;
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool;
|
|
||||||
|
|
||||||
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)]
|
|
||||||
pub struct InPlace<K: UnifyKey> {
|
|
||||||
values: sv::SnapshotVec<Delegate<K>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> fmt::Debug for InPlace<K>
|
|
||||||
where
|
|
||||||
K: UnifyKey,
|
|
||||||
K: Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.values.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range<usize> {
|
|
||||||
snapshot.value_count..self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue<Self::Key>) {
|
|
||||||
self.values.set_all(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.values.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.values.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> ops::IndexMut<usize> for InPlace<K>
|
|
||||||
where
|
|
||||||
K: UnifyKey,
|
|
||||||
{
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut VarValue<K> {
|
|
||||||
&mut 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: Vector<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: Vector::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 values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range<usize> {
|
|
||||||
snapshot.len()..self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn reset_unifications(&mut self, mut value: impl FnMut(usize) -> 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`. [NOTE: revisit in light of replacing dogged with im_rc!]
|
|
||||||
for i in 0..self.values.len() {
|
|
||||||
self.values[i] = value(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Vector.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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]
|
|
||||||
}
|
|
||||||
}
|
|
500
vendor/ena/src/unify/mod.rs
vendored
500
vendor/ena/src/unify/mod.rs
vendored
|
@ -1,500 +0,0 @@
|
||||||
// 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. As part of doing this, you can
|
|
||||||
//! define the "error" type to return on error; if errors are not
|
|
||||||
//! possible, use `NoError` (an uninstantiable struct). Using this
|
|
||||||
//! type also unlocks various more ergonomic methods (e.g., `union()`
|
|
||||||
//! in place of `unify_var_var()`).
|
|
||||||
//!
|
|
||||||
//! The best way to see how it is used is to read the `tests.rs` file;
|
|
||||||
//! search for e.g. `UnitKey`.
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
use std::marker;
|
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
mod backing_vec;
|
|
||||||
pub use self::backing_vec::{InPlace, UnificationStore};
|
|
||||||
|
|
||||||
#[cfg(feature = "persistent")]
|
|
||||||
pub use self::backing_vec::Persistent;
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A struct which can never be instantiated. Used
|
|
||||||
/// for the error type for infallible cases.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NoError {
|
|
||||||
_dummy: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)]
|
|
||||||
pub struct VarValue<K: UnifyKey> {
|
|
||||||
// FIXME pub
|
|
||||||
parent: K, // if equal to self, this is a root
|
|
||||||
pub value: K::Value, // value assigned (only relevant to root)
|
|
||||||
rank: u32, // max depth (only relevant to root)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> fmt::Debug for VarValue<K>
|
|
||||||
where
|
|
||||||
K: UnifyKey,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "p: {:?}, c: {:?}", self.parent, self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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, Default)]
|
|
||||||
pub struct UnificationTable<S: UnificationStore> {
|
|
||||||
/// Indicates the current value of each key.
|
|
||||||
values: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> fmt::Debug for UnificationTable<S>
|
|
||||||
where
|
|
||||||
S: UnificationStore,
|
|
||||||
S: Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.values.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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, // this is a root
|
|
||||||
value,
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn parent(&self, self_key: K) -> Option<K> {
|
|
||||||
self.if_not_self(self.parent, self_key)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn raw_parent(&self) -> K {
|
|
||||||
self.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
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() as u32;
|
|
||||||
let key: S::Key = UnifyKey::from_index(len);
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true iff there have been no keys created yet.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.values.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the keys of all variables created since the `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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtains the current value for a particular key.
|
|
||||||
/// Not for end-users; they can use `probe_value`.
|
|
||||||
pub fn value(&self, key: S::Key) -> &VarValue<S::Key> {
|
|
||||||
&self.values[key.index() as usize]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtains the current value for a particular key.
|
|
||||||
/// Not for end-users; they can use `probe_value`.
|
|
||||||
pub fn value_mut(&mut self, key: S::Key) -> &mut VarValue<S::Key> {
|
|
||||||
&mut 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.
|
|
||||||
///
|
|
||||||
/// This is an always-inlined version of this function for the hot
|
|
||||||
/// callsites. `uninlined_get_root_key` is the never-inlined version.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn inlined_get_root_key(&mut self, vid: S::Key) -> S::Key {
|
|
||||||
match self.value(vid).parent(vid) {
|
|
||||||
None => vid,
|
|
||||||
Some(redirect) => {
|
|
||||||
let root_key: S::Key = self.uninlined_get_root_key(redirect);
|
|
||||||
if root_key != redirect {
|
|
||||||
// Path compression
|
|
||||||
self.update_value(vid, |value| value.parent = root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
root_key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a never-inlined version of this function for cold callsites.
|
|
||||||
// 'inlined_get_root_key` is the always-inlined version.
|
|
||||||
#[inline(never)]
|
|
||||||
fn uninlined_get_root_key(&mut self, vid: S::Key) -> S::Key {
|
|
||||||
self.inlined_get_root_key(vid)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_root_key_without_compacting(&self, mut vid: S::Key) -> S::Key {
|
|
||||||
while let Some(redirect) = self.value(vid).parent(vid) {
|
|
||||||
vid = redirect;
|
|
||||||
}
|
|
||||||
|
|
||||||
vid
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_redirect(&self, vid: S::Key) -> bool {
|
|
||||||
self.value(vid).raw_parent() != vid
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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.
|
|
||||||
pub 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 {
|
|
||||||
match rank_a.cmp(&rank_b) {
|
|
||||||
Ordering::Greater => {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
// b has greater rank, so a should redirect to b.
|
|
||||||
self.redirect_root(rank_b, key_a, key_b, new_value);
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
// 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: Clone + Debug,
|
|
||||||
{
|
|
||||||
/// 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.inlined_get_root_key(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current value for the given key. If the key has
|
|
||||||
/// been union'd, this will give the value from the current root.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current value for the given key. If the key has
|
|
||||||
/// been union'd, this will give the value from the current root.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn probe_value_ref<K1>(&self, id: K1) -> &VarValue<K>
|
|
||||||
where
|
|
||||||
K1: Into<K>,
|
|
||||||
{
|
|
||||||
let id = id.into();
|
|
||||||
let id = self.get_root_key_without_compacting(id);
|
|
||||||
self.value(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current value for the given key. If the key has
|
|
||||||
/// been union'd, this will give the value from the current root.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn probe_value_ref_mut<K1>(&mut self, id: K1) -> &mut VarValue<K>
|
|
||||||
where
|
|
||||||
K1: Into<K>,
|
|
||||||
{
|
|
||||||
let id = id.into();
|
|
||||||
let id = self.inlined_get_root_key(id);
|
|
||||||
self.value_mut(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is for a debug_assert! in solve() only. Do not use it elsewhere!
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn probe_value_without_compacting<K1>(&self, id: K1) -> V
|
|
||||||
where
|
|
||||||
K1: Into<K>,
|
|
||||||
{
|
|
||||||
let id = id.into();
|
|
||||||
let id = self.get_root_key_without_compacting(id);
|
|
||||||
|
|
||||||
self.value(id).value.clone()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue