Skip to content

Commit 2ab56cb

Browse files
committed
Use NonZeroUsize inside NodeId
This allows `Option<NodeId>` to be no larger than `usize`, and saves 32 bytes of memory per node. To allow IDs to be used directly as indexes, the `Vec<Node<T>>` storage has an **uninitialized** item at index 0. Safety-wise, this "infects" the entire crate: every access to this `Vec` needs to make sure to skip that first (non-) item.
1 parent 6b6217c commit 2ab56cb

File tree

2 files changed

+80
-21
lines changed

2 files changed

+80
-21
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: 59 additions & 14 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> {
@@ -64,7 +93,7 @@ fn _static_assert_size_of_node() {
6493
// "Instanciating" the generic `transmute` function without calling it
6594
// still triggers the magic compile-time check
6695
// that input and output types have the same `size_of()`.
67-
let _ = std::mem::transmute::<Node<()>, [usize; 9]>;
96+
let _ = std::mem::transmute::<Node<()>, [usize; 5]>;
6897
}
6998

7099
impl<T> Node<T> {
@@ -120,33 +149,42 @@ impl<'a, T: 'a> PartialEq for NodeRef<'a, T> {
120149
impl<T> Tree<T> {
121150
/// Creates a tree with a root node.
122151
pub fn new(root: T) -> Self {
123-
Tree { vec: vec![Node::new(root)] }
152+
Self::with_capacity(root, 1)
124153
}
125154

126155
/// Creates a tree with a root node and the specified capacity.
127156
pub fn with_capacity(root: T, capacity: usize) -> Self {
128-
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
129167
vec.push(Node::new(root));
130168
Tree { vec }
131169
}
132170

133171
/// Returns a reference to the specified node.
134172
pub fn get(&self, id: NodeId) -> Option<NodeRef<T>> {
135-
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 })
136174
}
137175

138176
/// Returns a mutator of the specified node.
139177
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<T>> {
140-
let exists = self.vec.get(id.0).map(|_| ());
178+
let exists = self.vec.get(id.0.get()).map(|_| ());
141179
exists.map(move |_| NodeMut { id, tree: self })
142180
}
143181

144182
unsafe fn node(&self, id: NodeId) -> &Node<T> {
145-
self.vec.get_unchecked(id.0)
183+
self.vec.get_unchecked(id.0.get())
146184
}
147185

148186
unsafe fn node_mut(&mut self, id: NodeId) -> &mut Node<T> {
149-
self.vec.get_unchecked_mut(id.0)
187+
self.vec.get_unchecked_mut(id.0.get())
150188
}
151189

152190
/// Returns a reference to the specified node.
@@ -161,17 +199,19 @@ impl<T> Tree<T> {
161199

162200
/// Returns a reference to the root node.
163201
pub fn root(&self) -> NodeRef<T> {
164-
unsafe { self.get_unchecked(NodeId(0)) }
202+
unsafe { self.get_unchecked(ROOT) }
165203
}
166204

167205
/// Returns a mutator of the root node.
168206
pub fn root_mut(&mut self) -> NodeMut<T> {
169-
unsafe { self.get_unchecked_mut(NodeId(0)) }
207+
unsafe { self.get_unchecked_mut(ROOT) }
170208
}
171209

172210
/// Creates an orphan node.
173211
pub fn orphan(&mut self, value: T) -> NodeMut<T> {
174-
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()) });
175215
self.vec.push(Node::new(value));
176216
unsafe { self.get_unchecked_mut(id) }
177217
}
@@ -615,8 +655,8 @@ macro_rules! tree {
615655
impl<T: Debug> Debug for Tree<T> {
616656
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
617657
use iter::Edge;
658+
write!(f, "Tree {{")?;
618659
if f.alternate() {
619-
write!(f, "Tree {{")?;
620660
for edge in self.root().traverse() {
621661
match edge {
622662
Edge::Open(node) if node.has_children() => {
@@ -640,7 +680,12 @@ impl<T: Debug> Debug for Tree<T> {
640680
}
641681
write!(f, " }}")
642682
} else {
643-
f.debug_struct("Tree").field("vec", &self.vec).finish()
683+
write!(f, "Tree {{ [<uninitialized>")?;
684+
for node in &self.vec[1..] {
685+
write!(f, ", ")?;
686+
node.fmt(f)?;
687+
}
688+
write!(f, "] }}")
644689
}
645690
}
646691
}

0 commit comments

Comments
 (0)