Skip to main content

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}