1
Fork 0

Redefine NodeIndex as a newtype_index!.

This commit removes the custom index implementation of `NodeIndex`,
which probably predates `newtype_index!`.

As well as eliminating code, it improves the debugging experience,
because the custom implementation had the property of being incremented
by 1 (so it could use `NonZeroU32`), which was incredibly confusing if
you didn't expect it.

For some reason, I also had to remove an `unsafe` block marker from
`from_u32_unchecked()` that the compiler said was now unnecessary.
This commit is contained in:
Nicholas Nethercote 2019-09-16 11:53:12 +10:00
parent 04b1111ae8
commit 43c0d2ce8e
4 changed files with 35 additions and 42 deletions

View file

@ -149,7 +149,7 @@ macro_rules! newtype_index {
#[inline]
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
unsafe { $type { private: value } }
$type { private: value }
}
/// Extracts the value of this index as an integer.

View file

@ -74,9 +74,9 @@ impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O
.flat_map(|i| {
let node = &self.nodes[i];
node.parent.iter().map(|p| p.get())
.chain(node.dependents.iter().map(|p| p.get()))
.map(move |p| (p, i))
node.parent.iter()
.chain(node.dependents.iter())
.map(move |p| (p.index(), i))
})
.collect()
}

View file

@ -81,6 +81,8 @@
//! nodes, which aren't needed anymore.
use crate::fx::{FxHashMap, FxHashSet};
use crate::indexed_vec::Idx;
use crate::newtype_index;
use std::cell::Cell;
use std::collections::hash_map::Entry;
@ -88,14 +90,15 @@ use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;
mod node_index;
use self::node_index::NodeIndex;
mod graphviz;
#[cfg(test)]
mod tests;
newtype_index! {
pub struct NodeIndex { .. }
}
pub trait ForestObligation : Clone + Debug {
type Predicate : Clone + hash::Hash + Eq + Debug;
@ -151,6 +154,10 @@ pub struct ObligationForest<O: ForestObligation> {
/// At all times we maintain the invariant that every node appears
/// at a higher index than its parent. This is needed by the
/// backtrace iterator (which uses `split_at`).
///
/// Ideally, this would be an `IndexVec<NodeIndex, Node<O>>`. But that is
/// slower, because this vector is accessed so often that the
/// `u32`-to-`usize` conversions required for accesses are significant.
nodes: Vec<Node<O>>,
/// A cache of predicates that have been successfully completed.
@ -178,13 +185,19 @@ struct Node<O> {
obligation: O,
state: Cell<NodeState>,
/// The parent of a node - the original obligation of
/// which it is a subobligation. Except for error reporting,
/// it is just like any member of `dependents`.
/// The parent of a node - the original obligation of which it is a
/// subobligation. Except for error reporting, it is just like any member
/// of `dependents`.
///
/// Unlike `ObligationForest::nodes`, this uses `NodeIndex` rather than
/// `usize` for the index, because keeping the size down is more important
/// than the cost of converting to a `usize` for indexing.
parent: Option<NodeIndex>,
/// Obligations that depend on this obligation for their
/// completion. They must all be in a non-pending state.
/// Obligations that depend on this obligation for their completion. They
/// must all be in a non-pending state.
///
/// This uses `NodeIndex` for the same reason as `parent`.
dependents: Vec<NodeIndex>,
/// Identifier of the obligation tree to which this node belongs.
@ -294,7 +307,7 @@ impl<O: ForestObligation> ObligationForest<O> {
Entry::Occupied(o) => {
debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
obligation, parent, o.get());
let node = &mut self.nodes[o.get().get()];
let node = &mut self.nodes[o.get().index()];
if let Some(parent_index) = parent {
// If the node is already in `waiting_cache`, it's already
// been marked with a parent. (It's possible that parent
@ -318,7 +331,7 @@ impl<O: ForestObligation> ObligationForest<O> {
let obligation_tree_id = match parent {
Some(parent_index) => {
self.nodes[parent_index.get()].obligation_tree_id
self.nodes[parent_index.index()].obligation_tree_id
}
None => self.obligation_tree_id_generator.next().unwrap()
};
@ -506,7 +519,7 @@ impl<O: ForestObligation> ObligationForest<O> {
node.state.set(NodeState::OnDfsStack);
stack.push(i);
for index in node.parent.iter().chain(node.dependents.iter()) {
self.find_cycles_from_node(stack, processor, index.get());
self.find_cycles_from_node(stack, processor, index.index());
}
stack.pop();
node.state.set(NodeState::Done);
@ -531,11 +544,11 @@ impl<O: ForestObligation> ObligationForest<O> {
let node = &self.nodes[i];
node.state.set(NodeState::Error);
trace.push(node.obligation.clone());
error_stack.extend(node.dependents.iter().map(|index| index.get()));
error_stack.extend(node.dependents.iter().map(|index| index.index()));
// Loop to the parent.
match node.parent {
Some(parent_index) => i = parent_index.get(),
Some(parent_index) => i = parent_index.index(),
None => break
}
}
@ -548,7 +561,7 @@ impl<O: ForestObligation> ObligationForest<O> {
}
error_stack.extend(
node.parent.iter().chain(node.dependents.iter()).map(|index| index.get())
node.parent.iter().chain(node.dependents.iter()).map(|index| index.index())
);
}
@ -560,7 +573,7 @@ impl<O: ForestObligation> ObligationForest<O> {
#[inline(always)]
fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
for dependent in node.parent.iter().chain(node.dependents.iter()) {
self.mark_as_waiting_from(&self.nodes[dependent.get()]);
self.mark_as_waiting_from(&self.nodes[dependent.index()]);
}
}
@ -686,7 +699,7 @@ impl<O: ForestObligation> ObligationForest<O> {
for node in &mut self.nodes {
if let Some(index) = node.parent {
let new_i = node_rewrites[index.get()];
let new_i = node_rewrites[index.index()];
if new_i >= nodes_len {
// parent dead due to error
node.parent = None;
@ -697,7 +710,7 @@ impl<O: ForestObligation> ObligationForest<O> {
let mut i = 0;
while i < node.dependents.len() {
let new_i = node_rewrites[node.dependents[i].get()];
let new_i = node_rewrites[node.dependents[i].index()];
if new_i >= nodes_len {
node.dependents.swap_remove(i);
} else {
@ -709,7 +722,7 @@ impl<O: ForestObligation> ObligationForest<O> {
let mut kill_list = vec![];
for (predicate, index) in &mut self.waiting_cache {
let new_i = node_rewrites[index.get()];
let new_i = node_rewrites[index.index()];
if new_i >= nodes_len {
kill_list.push(predicate.clone());
} else {

View file

@ -1,20 +0,0 @@
use std::num::NonZeroU32;
use std::u32;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct NodeIndex {
index: NonZeroU32,
}
impl NodeIndex {
#[inline]
pub fn new(value: usize) -> NodeIndex {
assert!(value < (u32::MAX as usize));
NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() }
}
#[inline]
pub fn get(self) -> usize {
(self.index.get() - 1) as usize
}
}