Skip to content

Commit 98cdce0

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.
1 parent 6b6217c commit 98cdce0

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

src/iter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ impl<'a, T: 'a> ExactSizeIterator for Nodes<'a, T> { }
8080
impl<'a, T: 'a> Iterator for Nodes<'a, T> {
8181
type Item = NodeRef<'a, T>;
8282
fn next(&mut self) -> Option<Self::Item> {
83-
self.iter.next().map(|i| unsafe { self.tree.get_unchecked(NodeId(i)) })
83+
self.iter.next().map(|i| unsafe { self.tree.get_unchecked(NodeId::from_index(i)) })
8484
}
8585
fn size_hint(&self) -> (usize, Option<usize>) {
8686
self.iter.size_hint()
8787
}
8888
}
8989
impl<'a, T: 'a> DoubleEndedIterator for Nodes<'a, T> {
9090
fn next_back(&mut self) -> Option<Self::Item> {
91-
self.iter.next_back().map(|i| unsafe { self.tree.get_unchecked(NodeId(i)) })
91+
self.iter.next_back().map(|i| unsafe { self.tree.get_unchecked(NodeId::from_index(i)) })
9292
}
9393
}
9494

src/lib.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
)]
3737

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

4041
/// Vec-backed ID-tree.
4142
///
@@ -49,7 +50,20 @@ pub struct Tree<T> {
4950
///
5051
/// Index into a `Tree`-internal `Vec`.
5152
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52-
pub struct NodeId(usize);
53+
pub struct NodeId(NonZeroUsize);
54+
55+
impl NodeId {
56+
// Safety: `n` must not equal `usize::MAX`.
57+
// (This is never the case for `Vec::len()`, that would mean it owns
58+
// the entire address space without leaving space for even the its pointer.)
59+
unsafe fn from_index(n: usize) -> Self {
60+
NodeId(NonZeroUsize::new_unchecked(n + 1))
61+
}
62+
63+
fn to_index(self) -> usize {
64+
self.0.get() - 1
65+
}
66+
}
5367

5468
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5569
struct Node<T> {
@@ -64,7 +78,7 @@ fn _static_assert_size_of_node() {
6478
// "Instanciating" the generic `transmute` function without calling it
6579
// still triggers the magic compile-time check
6680
// that input and output types have the same `size_of()`.
67-
let _ = std::mem::transmute::<Node<()>, [usize; 9]>;
81+
let _ = std::mem::transmute::<Node<()>, [usize; 5]>;
6882
}
6983

7084
impl<T> Node<T> {
@@ -132,21 +146,21 @@ impl<T> Tree<T> {
132146

133147
/// Returns a reference to the specified node.
134148
pub fn get(&self, id: NodeId) -> Option<NodeRef<T>> {
135-
self.vec.get(id.0).map(|node| NodeRef { id, node, tree: self })
149+
self.vec.get(id.to_index()).map(|node| NodeRef { id, node, tree: self })
136150
}
137151

138152
/// Returns a mutator of the specified node.
139153
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<T>> {
140-
let exists = self.vec.get(id.0).map(|_| ());
154+
let exists = self.vec.get(id.to_index()).map(|_| ());
141155
exists.map(move |_| NodeMut { id, tree: self })
142156
}
143157

144158
unsafe fn node(&self, id: NodeId) -> &Node<T> {
145-
self.vec.get_unchecked(id.0)
159+
self.vec.get_unchecked(id.to_index())
146160
}
147161

148162
unsafe fn node_mut(&mut self, id: NodeId) -> &mut Node<T> {
149-
self.vec.get_unchecked_mut(id.0)
163+
self.vec.get_unchecked_mut(id.to_index())
150164
}
151165

152166
/// Returns a reference to the specified node.
@@ -161,17 +175,17 @@ impl<T> Tree<T> {
161175

162176
/// Returns a reference to the root node.
163177
pub fn root(&self) -> NodeRef<T> {
164-
unsafe { self.get_unchecked(NodeId(0)) }
178+
unsafe { self.get_unchecked(NodeId::from_index(0)) }
165179
}
166180

167181
/// Returns a mutator of the root node.
168182
pub fn root_mut(&mut self) -> NodeMut<T> {
169-
unsafe { self.get_unchecked_mut(NodeId(0)) }
183+
unsafe { self.get_unchecked_mut(NodeId::from_index(0)) }
170184
}
171185

172186
/// Creates an orphan node.
173187
pub fn orphan(&mut self, value: T) -> NodeMut<T> {
174-
let id = NodeId(self.vec.len());
188+
let id = unsafe { NodeId::from_index(self.vec.len()) };
175189
self.vec.push(Node::new(value));
176190
unsafe { self.get_unchecked_mut(id) }
177191
}

0 commit comments

Comments
 (0)