Skip to content

Commit 52169be

Browse files
authored
Merge pull request #17 from SimonSapin/nonzero
Use NonZeroUsize inside NodeId
2 parents e164eec + 2ab56cb commit 52169be

File tree

2 files changed

+86
-20
lines changed

2 files changed

+86
-20
lines changed

src/iter.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use std::{slice, vec};
1+
use std::{mem, slice, vec};
2+
use std::num::NonZeroUsize;
23
use std::ops::Range;
34

45
use {Tree, NodeId, Node, NodeRef};
@@ -77,43 +78,56 @@ impl<'a, T: 'a> Clone for Nodes<'a, T> {
7778
}
7879
}
7980
impl<'a, T: 'a> ExactSizeIterator for Nodes<'a, T> { }
81+
impl<'a, T: 'a> Nodes<'a, T> {
82+
unsafe fn from_index(&self, i: usize) -> NodeRef<'a, T> {
83+
self.tree.get_unchecked(NodeId(NonZeroUsize::new_unchecked(i)))
84+
}
85+
}
8086
impl<'a, T: 'a> Iterator for Nodes<'a, T> {
8187
type Item = NodeRef<'a, T>;
8288
fn next(&mut self) -> Option<Self::Item> {
83-
self.iter.next().map(|i| unsafe { self.tree.get_unchecked(NodeId(i)) })
89+
// Safety: `i` is in `1..self.vec.len()`, so it is non-zero and in bounds.
90+
self.iter.next().map(|i| unsafe { self.from_index(i) })
8491
}
8592
fn size_hint(&self) -> (usize, Option<usize>) {
8693
self.iter.size_hint()
8794
}
8895
}
8996
impl<'a, T: 'a> DoubleEndedIterator for Nodes<'a, T> {
9097
fn next_back(&mut self) -> Option<Self::Item> {
91-
self.iter.next_back().map(|i| unsafe { self.tree.get_unchecked(NodeId(i)) })
98+
// Safety: `i` is in `1..self.vec.len()`, so it is non-zero and in bounds.
99+
self.iter.next_back().map(|i| unsafe { self.from_index(i) })
92100
}
93101
}
94102

95103
impl<T> IntoIterator for Tree<T> {
96104
type Item = T;
97105
type IntoIter = IntoIter<T>;
98106
fn into_iter(self) -> Self::IntoIter {
99-
IntoIter(self.vec.into_iter())
107+
let mut iter = self.vec.into_iter();
108+
// Don’t yield the uninitialized node at index 0 or run its destructor.
109+
mem::forget(iter.next());
110+
IntoIter(iter)
100111
}
101112
}
102113

103114
impl<T> Tree<T> {
104115
/// Returns an iterator over values in insert order.
105116
pub fn values(&self) -> Values<T> {
106-
Values(self.vec.iter())
117+
// Skip over the uninitialized node at index 0
118+
Values(self.vec[1..].iter())
107119
}
108120

109121
/// Returns a mutable iterator over values in insert order.
110122
pub fn values_mut(&mut self) -> ValuesMut<T> {
111-
ValuesMut(self.vec.iter_mut())
123+
// Skip over the uninitialized node at index 0
124+
ValuesMut(self.vec[1..].iter_mut())
112125
}
113126

114127
/// Returns an iterator over nodes in insert order.
115128
pub fn nodes(&self) -> Nodes<T> {
116-
Nodes { tree: self, iter: 0..self.vec.len() }
129+
// Skip over the uninitialized node at index 0
130+
Nodes { tree: self, iter: 1..self.vec.len() }
117131
}
118132
}
119133

src/lib.rs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,49 @@
3636
)]
3737

3838
use std::fmt::{self, Debug, Formatter};
39+
use std::num::NonZeroUsize;
3940

4041
/// Vec-backed ID-tree.
4142
///
4243
/// Always contains at least a root node.
43-
#[derive(Clone, PartialEq, Eq, Hash)]
4444
pub struct Tree<T> {
45+
// Safety note: node at index 0 is uninitialized!
4546
vec: Vec<Node<T>>,
4647
}
4748

49+
impl<T> Clone for Tree<T> where T: Clone {
50+
fn clone(&self) -> Self {
51+
let mut vec = Vec::with_capacity(self.vec.len());
52+
// See Tree::with_capacity
53+
unsafe {
54+
vec.set_len(1);
55+
}
56+
vec.extend(self.vec[1..].iter().cloned());
57+
Tree { vec }
58+
}
59+
}
60+
61+
impl<T> std::hash::Hash for Tree<T> where T: std::hash::Hash {
62+
fn hash<H>(&self, state: &mut H) where H: std::hash::Hasher {
63+
self.vec[1..].hash(state)
64+
}
65+
}
66+
67+
impl<T> Eq for Tree<T> where T: Eq {}
68+
impl<T> PartialEq for Tree<T> where T: PartialEq {
69+
fn eq(&self, other: &Self) -> bool {
70+
self.vec[1..] == other.vec[1..]
71+
}
72+
}
73+
74+
4875
/// Node ID.
4976
///
5077
/// Index into a `Tree`-internal `Vec`.
5178
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52-
pub struct NodeId(usize);
79+
pub struct NodeId(NonZeroUsize);
80+
81+
const ROOT: NodeId = NodeId(unsafe { NonZeroUsize::new_unchecked(1) });
5382

5483
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5584
struct Node<T> {
@@ -60,6 +89,13 @@ struct Node<T> {
6089
value: T,
6190
}
6291

92+
fn _static_assert_size_of_node() {
93+
// "Instanciating" the generic `transmute` function without calling it
94+
// still triggers the magic compile-time check
95+
// that input and output types have the same `size_of()`.
96+
let _ = std::mem::transmute::<Node<()>, [usize; 5]>;
97+
}
98+
6399
impl<T> Node<T> {
64100
fn new(value: T) -> Self {
65101
Node {
@@ -113,33 +149,42 @@ impl<'a, T: 'a> PartialEq for NodeRef<'a, T> {
113149
impl<T> Tree<T> {
114150
/// Creates a tree with a root node.
115151
pub fn new(root: T) -> Self {
116-
Tree { vec: vec![Node::new(root)] }
152+
Self::with_capacity(root, 1)
117153
}
118154

119155
/// Creates a tree with a root node and the specified capacity.
120156
pub fn with_capacity(root: T, capacity: usize) -> Self {
121-
let mut vec = Vec::with_capacity(capacity);
157+
let mut vec = Vec::with_capacity(capacity.saturating_add(1));
158+
// The node at index 0 is unused and uninitialized.
159+
// This allows using NonZeroUsize directly as an index.
160+
//
161+
// Safety: we requested at least 1 of capacity, so this is in bounds.
162+
// It is up to the rest of the crate to not access this uninitialized node.
163+
unsafe {
164+
vec.set_len(1);
165+
}
166+
// The root node is at index 1
122167
vec.push(Node::new(root));
123168
Tree { vec }
124169
}
125170

126171
/// Returns a reference to the specified node.
127172
pub fn get(&self, id: NodeId) -> Option<NodeRef<T>> {
128-
self.vec.get(id.0).map(|node| NodeRef { id, node, tree: self })
173+
self.vec.get(id.0.get()).map(|node| NodeRef { id, node, tree: self })
129174
}
130175

131176
/// Returns a mutator of the specified node.
132177
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<T>> {
133-
let exists = self.vec.get(id.0).map(|_| ());
178+
let exists = self.vec.get(id.0.get()).map(|_| ());
134179
exists.map(move |_| NodeMut { id, tree: self })
135180
}
136181

137182
unsafe fn node(&self, id: NodeId) -> &Node<T> {
138-
self.vec.get_unchecked(id.0)
183+
self.vec.get_unchecked(id.0.get())
139184
}
140185

141186
unsafe fn node_mut(&mut self, id: NodeId) -> &mut Node<T> {
142-
self.vec.get_unchecked_mut(id.0)
187+
self.vec.get_unchecked_mut(id.0.get())
143188
}
144189

145190
/// Returns a reference to the specified node.
@@ -154,17 +199,19 @@ impl<T> Tree<T> {
154199

155200
/// Returns a reference to the root node.
156201
pub fn root(&self) -> NodeRef<T> {
157-
unsafe { self.get_unchecked(NodeId(0)) }
202+
unsafe { self.get_unchecked(ROOT) }
158203
}
159204

160205
/// Returns a mutator of the root node.
161206
pub fn root_mut(&mut self) -> NodeMut<T> {
162-
unsafe { self.get_unchecked_mut(NodeId(0)) }
207+
unsafe { self.get_unchecked_mut(ROOT) }
163208
}
164209

165210
/// Creates an orphan node.
166211
pub fn orphan(&mut self, value: T) -> NodeMut<T> {
167-
let id = NodeId(self.vec.len());
212+
// Safety: vec.len() starts at 2 in Self::with_capacity and never shrinks,
213+
// so it is non-zero.
214+
let id = NodeId(unsafe { NonZeroUsize::new_unchecked(self.vec.len()) });
168215
self.vec.push(Node::new(value));
169216
unsafe { self.get_unchecked_mut(id) }
170217
}
@@ -628,8 +675,8 @@ macro_rules! tree {
628675
impl<T: Debug> Debug for Tree<T> {
629676
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
630677
use iter::Edge;
678+
write!(f, "Tree {{")?;
631679
if f.alternate() {
632-
write!(f, "Tree {{")?;
633680
for edge in self.root().traverse() {
634681
match edge {
635682
Edge::Open(node) if node.has_children() => {
@@ -653,7 +700,12 @@ impl<T: Debug> Debug for Tree<T> {
653700
}
654701
write!(f, " }}")
655702
} else {
656-
f.debug_struct("Tree").field("vec", &self.vec).finish()
703+
write!(f, "Tree {{ [<uninitialized>")?;
704+
for node in &self.vec[1..] {
705+
write!(f, ", ")?;
706+
node.fmt(f)?;
707+
}
708+
write!(f, "] }}")
657709
}
658710
}
659711
}

0 commit comments

Comments
 (0)