stable_vec/core/option.rs
1use ::core::{
2 fmt,
3 hint::unreachable_unchecked,
4 mem::size_of,
5 ptr,
6};
7
8use alloc::vec::Vec;
9
10use super::Core;
11
12/// A `Core` implementation that is essentially a `Vec<Option<T>>`.
13///
14/// This implementation is quite different from the `BitVecCore`. This one only
15/// manages one allocation, meaning it does not suffer from the same
16/// disadvantages as `BitVecCore`. This can sometimes lead to better memory
17/// access times due to caching effects. However, this implementation has the
18/// major disadvantage of wasting memory in most cases.
19///
20/// Usually, `size_of::<Option<T>>() > size_of::<T>()`. The difference can be
21/// as high as 4 byte due to alignment. But as only one bit is used to store
22/// the `None/Some` information, all that memory is wasted. A worst case
23/// scenario is something like `Option<u32>`: this is 8 byte large (on most
24/// platforms), meaning that a stable vector with `OptionCore` would use twice
25/// as much memory as a `Vec<u32>`. This is not only wasteful, but has a
26/// negative effect on speed as the information is not very densely packed.
27///
28/// In general, only use this implementation in one of these cases:
29///
30/// - Your `T` is `NonNull`, meaning that `Option<T>` has the same size as `T`.
31/// This is then even more memory efficient than the default core
32/// implementation. Iterating over indices of a stable vector is still slower
33/// in this case as the relevant information is further apart.
34/// - Your `T` is very large, meaning that the amount of wasted memory is small
35/// in comparison.
36///
37/// In both cases, switching the implementation from default to this only makes
38/// sense after you measured that you actually gain performance from it. The
39/// interface of both implementations is exactly the same.
40pub struct OptionCore<T> {
41 /// The data and deleted information in one.
42 ///
43 /// The `len` and `capacity` properties of the vector directly correspond
44 /// to `len` and `cap` properties of the `Core` trait. However, as a `Vec`
45 /// assumes that everything beyond `len` is uninitialized, we have to make
46 /// sure to only interact with it in a particular way.
47 ///
48 /// This vector is in a correct state at all times. This means that the
49 /// vector can simply be dropped and it wouldn't access uninitialized
50 /// values or leak memory.
51 ///
52 /// This implementation has one potentially problematic assumption. When we
53 /// allocate new memory, we initialize all slots to `None`. That way we can
54 /// access all slots with indices < cap. However, the `Vec` docs state:
55 ///
56 /// > Its uninitialized memory is scratch space that it may use however it
57 /// > wants. It will generally just do whatever is most efficient or
58 /// > otherwise easy to implement. [...] There is one case which we will
59 /// > not break, however: using `unsafe` code to write to the excess
60 /// > capacity, and then increasing the length to match, is always valid.
61 ///
62 /// This probably says that we cannot rely on the content of the excess
63 /// capacity memory. However, we are careful how we touch the vector and we
64 /// do not use any methods that would benefit in any way from touching that
65 /// memory. Therefore we assume that all slots with indices > len stay
66 /// initialized to `None`. A couple of methods rely on that assumption.
67 data: Vec<Option<T>>,
68}
69
70impl<T> Core<T> for OptionCore<T> {
71 fn new() -> Self {
72 Self {
73 data: Vec::new(),
74 }
75 }
76
77 fn len(&self) -> usize {
78 self.data.len()
79 }
80
81 fn cap(&self) -> usize {
82 if size_of::<Option<T>>() == 0 {
83 // `Vec` reports a capacity of `usize::MAX` for zero sized types,
84 // which would violate the `Core` invariant `cap ≤ isize::MAX`.
85 isize::max_value() as usize
86 } else {
87 self.data.capacity()
88 }
89 }
90
91 unsafe fn set_len(&mut self, new_len: usize) {
92 debug_assert!(new_len <= self.cap());
93 // Other precondition is too expensive to test, even in debug:
94 // ∀ i in `new_len..self.cap()` ⇒ `self.has_element_at(i) == false`
95
96 // We can just call `set_len` on the vector as both of that method's
97 // preconditions are held:
98 // - "new_len must be less than or equal to capacity()": this is also a
99 // direct precondition of this method.
100 // - "The elements at old_len..new_len must be initialized": all slots
101 // of the vector are always initialized. On allocation, everything is
102 // initialized to `None`. All slots in `old_len..new_len` are always
103 // `None` as stated by the `Core` invariant "`len ≤ i < cap`: slots
104 // with index `i` are always empty".
105 self.data.set_len(new_len)
106 }
107
108 #[inline(never)]
109 #[cold]
110 unsafe fn realloc(&mut self, new_cap: usize) {
111 debug_assert!(new_cap >= self.len());
112 debug_assert!(new_cap <= isize::max_value() as usize);
113
114 // Do different things depending on whether we shrink or grow.
115 let old_cap = self.cap();
116 let initialized_end = if new_cap > old_cap {
117 // ----- We will grow the vector -----
118
119 // We use `reserve_exact` here instead of creating a new vector,
120 // because the former can use `realloc` which is significantly faster
121 // in many cases. See https://stackoverflow.com/a/39562813/2408867
122 let additional = new_cap - self.data.len();
123 self.data.reserve_exact(additional);
124
125 // `Vec` preserves all elements up to its length. Beyond that, the
126 // slots might have become uninitialized by `reserve_exact`. Thus
127 // we need to initialize them again.
128 self.data.len()
129 } else if new_cap < old_cap {
130 // We will shrink the vector. The only tool we have for this is
131 // `shrink_to_fit`. In order to use this, we temporarily have to
132 // set the length of the vector to the new capacity. This is fine:
133 //
134 // - If `new_cap < old_len`, we temporarily remove elements from
135 // the vector. But these are all `None`s as guaranteed by the
136 // preconditions.
137 // - If `new_cap > old_len`, we temporarily add elements to the
138 // vector. But these have all been initialized to `None`.
139 let old_len = self.data.len();
140 self.data.set_len(new_cap);
141 self.data.shrink_to_fit();
142 self.data.set_len(old_len);
143
144 // When calling `shrink_to_fit`, the `Vec` cannot do anything funky
145 // with the elements up to its size (which at that time was
146 // `new_cap`). However, all memory that might exist beyond that
147 // (i.e. if `shrink_to_fit` does not manage to perfectly fit) might
148 // be uninitialized now.
149 new_cap
150 } else {
151 // If the requested capacity is exactly the current one, we do
152 // nothing. We return the current capacity from this expression to
153 // say that all elements are indeed initialized.
154 self.data.capacity()
155 };
156
157 // We now need to potentially initialize some elements to `None`. The
158 // index `initialized_end` tells us the end of the range where all
159 // elements are guaranteed to be initialized. Thus we need to
160 // initialize `initialized_end..self.data.capacity()`.
161 let actual_capacity = self.data.capacity();
162 let mut ptr = self.data.as_mut_ptr().add(initialized_end);
163 let end = self.data.as_mut_ptr().add(actual_capacity);
164 while ptr != end {
165 ptr::write(ptr, None);
166 ptr = ptr.add(1);
167 }
168 }
169
170 /// Assumes that `idx < capacity`
171 unsafe fn has_element_at(&self, idx: usize) -> bool {
172 debug_assert!(idx < self.cap());
173 // Under the precondition that we maintain `None` values,
174 // for all items removed from the array and
175 // all extra capacity not containing items.
176 //
177 // Given that this is maintained during removal of items,
178 // realloc, and during clear. We can get a valid reference
179 // to an option for any idx < self.cap.
180 (&*self.data.as_ptr().add(idx)).is_some()
181 }
182
183 unsafe fn insert_at(&mut self, idx: usize, elem: T) {
184 debug_assert!(idx < self.cap());
185 debug_assert!(self.has_element_at(idx) == false);
186
187 // We use `ptr::write` instead of a simple assignment here for
188 // performance reason. An assignment would try to drop the value on the
189 // left hand side. Since we know from our preconditions that this value
190 // is in fact `None` and we thus never need to drop it, `ptr::write` is
191 // faster.
192 ptr::write(self.data.as_mut_ptr().add(idx), Some(elem));
193 }
194
195 unsafe fn remove_at(&mut self, idx: usize) -> T {
196 debug_assert!(idx < self.cap());
197 debug_assert!(self.has_element_at(idx));
198
199 // Just like in `get_unchecked_mut`, we avoid creating a reference to
200 // the whole vector here.
201 match (*self.data.as_mut_ptr().add(idx)).take() {
202 // The precondition guarantees us that the slot is not empty, thus
203 // we use this unsafe `unreachable_unchecked` to omit the branch.
204 None => unreachable_unchecked(),
205 Some(elem) => elem,
206 }
207 }
208
209 unsafe fn get_unchecked(&self, idx: usize) -> &T {
210 debug_assert!(idx < self.cap());
211 debug_assert!(self.has_element_at(idx));
212
213 match self.data.get_unchecked(idx) {
214 // The precondition guarantees us that the slot is not empty, thus
215 // we use this unsafe `unreachable_unchecked` to omit the branch.
216 None => unreachable_unchecked(),
217 Some(elem) => elem,
218 }
219 }
220
221 unsafe fn get_unchecked_mut(&mut self, idx: usize) -> &mut T {
222 debug_assert!(idx < self.cap());
223 debug_assert!(self.has_element_at(idx));
224
225 // We deliberately do not use `self.data.get_unchecked_mut(idx)`
226 // here: that goes through `DerefMut` and thus creates a `&mut
227 // [Option<T>]` spanning the whole vector. Such a reference invalidates
228 // all references to elements that were handed out earlier. And
229 // `IterMut` does hand out references with an extended lifetime which
230 // have to stay valid while the iterator advances!
231 match &mut *self.data.as_mut_ptr().add(idx) {
232 // The precondition guarantees us that the slot is not empty, thus
233 // we use this unsafe `unreachable_unchecked` to omit the branch.
234 None => unreachable_unchecked(),
235 Some(elem) => elem,
236 }
237 }
238
239 fn clear(&mut self) {
240 // We can assume that all existing elements have an index lower than
241 // `len` (this is one of the invariants of the `Core` interface).
242 // Calling `clear` on the `Vec` would drop all remaining elements and
243 // sets the length to 0. However those values would subsequently become
244 // uninitialized. Thus we call take for each item to leave a
245 // `None` value in it's place and set the length to zero.
246 for item in self.data.iter_mut() {
247 drop(item.take());
248 }
249 unsafe {
250 self.set_len(0);
251 }
252 }
253
254 unsafe fn swap(&mut self, a: usize, b: usize) {
255 // We can't just have two mutable references, so we use `ptr::swap`
256 // instead of `mem::swap`. We do not use the slice's `swap` method as
257 // that performs bound checks.
258 let p = self.data.as_mut_ptr();
259 let pa: *mut _ = p.add(a);
260 let pb: *mut _ = p.add(b);
261 ptr::swap(pa, pb);
262 }
263}
264
265impl<T: Clone> Clone for OptionCore<T> {
266 fn clone(&self) -> Self {
267 // Cloning the vector is safe: the `Vec` implementation won't access
268 // uninitialized memory. However, simply cloning it would be wrong for
269 // two reasons:
270 //
271 // - `Vec` might not retain the same capacity when cloning it. But this
272 // is important for us.
273 // - The memory after its length is probably uninitialized.
274 //
275 // To fix both issues, we create a new vec with the appopriate capacity
276 // and extend it with the values of the other. Placing None objects in
277 // the extra capacity and then set the length.
278 //
279 // Note that the vec might allocate more than the requested capacity, so
280 // we need to write `None` to all remaining slots.
281 if size_of::<Option<T>>() == 0 {
282 // Neither problem exists for zero sized slots: there is no memory
283 // that could be uninitialized and the capacity of the clone is
284 // `usize::MAX`, just like ours. Going through the code below would
285 // try to push `usize::MAX` many `None`s into the vector.
286 return Self { data: self.data.clone() };
287 }
288
289 let mut data = Vec::with_capacity(self.data.capacity());
290 data.extend(
291 self.data
292 .iter()
293 .cloned()
294 .chain(core::iter::repeat(None).take(data.capacity() - self.data.len())),
295 );
296 debug_assert_eq!(data.len(), data.capacity());
297 debug_assert!(data.capacity() >= self.data.capacity());
298 unsafe {
299 data.set_len(self.data.len());
300 }
301 Self { data }
302 }
303}
304
305impl<T> Drop for OptionCore<T> {
306 fn drop(&mut self) {
307 // We don't need to anything! The `Vec` will be dropped which is
308 // correct: that will drop all remaining elements but won't touch
309 // non-existing elements. This manual `Drop` impl still exists to
310 // explain this fact and to make sure the automatic `Drop` impl won't
311 // lead to unsafety in the future.
312 }
313}
314
315// This impl is usually not used. `StableVec` has its own impl which doesn't
316// use this one.
317impl<T: fmt::Debug> fmt::Debug for OptionCore<T> {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 f.debug_tuple("OptionCore")
320 .field(&self.data)
321 .finish()
322 }
323}