1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use std::ptr::NonNull;
/// Vector with generational indices
#[derive(Debug, Clone)]
pub struct GenVec<T> {
storage: Vec<GenEntry<T>>,
free_list: Vec<u32>,
}
#[derive(Debug, Clone)]
struct GenEntry<T> {
generation: u32,
item: Option<T>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GenIdx {
generation: u32,
index: u32,
}
impl<T> GenVec<T> {
pub fn new() -> Self {
Self {
storage: Vec::new(),
free_list: Vec::new(),
}
}
/// Returns the number of items in the vector, excluding free indices.
#[allow(dead_code)]
pub fn items(&self) -> usize {
self.storage.len() - self.free_list.len()
}
/// Replaces the item at the given raw index with a new item, returning the new [`GenIdx`] or
/// `None` if the index is invalid.
///
/// # Panics
///
/// Panic if the index is out of bounds
pub fn replace_index(&mut self, idx: u32, item: T) -> GenIdx {
self.storage
.get_mut(idx as usize)
.map(|old_entry| {
old_entry.generation += 1;
old_entry.item = Some(item);
GenIdx {
generation: old_entry.generation,
index: idx,
}
})
.expect("index out of bounds")
}
/// Pushes an item to the end of the vector, without reusing a free index.
pub fn push_end(&mut self, item: T) -> GenIdx {
let index = self.storage.len() as u32;
self.storage.push(GenEntry {
generation: 0,
item: Some(item),
});
GenIdx {
generation: 0,
index,
}
}
/// Pushes an item into the vector, possibly reusing a free index.
///
/// - If the vector is empty, it will push the item to the end.
/// - If the vector is not empty, it will reuse a free index if available. If no free index is
/// available, it will push the item to the end.
pub fn push(&mut self, item: T) -> GenIdx {
match self.free_list.pop() {
Some(index) => self.replace_index(index, item),
None => self.push_end(item),
}
}
/// Borrows the item at the given index, or `None` if the index is invalid.
pub fn get(&self, idx: GenIdx) -> Option<&T> {
let entry = self.storage.get(idx.index as usize)?;
if entry.generation == idx.generation {
entry.item.as_ref()
} else {
None
}
}
/// Mutably borrows the item at the given index, or `None` if the index is invalid.
#[allow(dead_code)]
pub fn get_mut(&mut self, idx: GenIdx) -> Option<&mut T> {
let entry = self.storage.get_mut(idx.index as usize)?;
if entry.generation == idx.generation {
entry.item.as_mut()
} else {
None
}
}
/// Returns the item at the given index, or `None` if the index is invalid.
pub fn remove(&mut self, idx: GenIdx) -> Option<T> {
let entry = self.storage.get_mut(idx.index as usize)?;
if entry.generation == idx.generation {
self.free_list.push(idx.index);
entry.item.take()
} else {
None
}
}
#[allow(dead_code)]
pub fn iter(&self) -> Iter<'_, T> {
Iter {
storage: &self.storage,
current: 0,
}
}
#[allow(dead_code)]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
let len = self.storage.len();
// SAFETY: self.storage is guaranteed to be non-null and valid.
let start = unsafe { NonNull::new_unchecked(self.storage.as_mut_ptr()) };
IterMut {
start,
current: 0,
len,
_marker: std::marker::PhantomData,
}
}
}
pub struct Iter<'a, T> {
storage: &'a Vec<GenEntry<T>>,
current: usize,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (GenIdx, &'a T);
fn next(&mut self) -> Option<Self::Item> {
while self.current < self.storage.len() {
let entry = &self.storage[self.current];
self.current += 1;
if let Some(item) = &entry.item {
return Some((
GenIdx {
generation: entry.generation,
index: self.current as u32 - 1,
},
item,
));
}
}
None
}
}
pub struct IterMut<'a, T> {
start: NonNull<GenEntry<T>>,
current: usize,
len: usize,
// Ensure the mutable borrow of GenVec<T> is valid for the lifetime of the iterator
_marker: std::marker::PhantomData<&'a mut T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (GenIdx, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
let entry = loop {
if self.current >= self.len {
return None;
}
// SAFETY: The caller needs to ensure that the `start` is a valid pointer to the first
// element of the vector and that the `length` is the length of the vector. It is
// guaranteed that `self.current` is less than `self.len`, so the pointer arithmetic is
// within bounds.
let entry = unsafe { &mut *self.start.as_ptr().add(self.current) };
match entry.item {
Some(_) => break entry,
None => self.current += 1,
}
};
let idx = GenIdx {
generation: entry.generation,
index: self.current as u32,
};
let item = entry.item.as_mut().expect("item is None");
self.current += 1;
Some((idx, item))
}
}