Skip to main content

stable_vec/core/
bitvec.rs

1use ::core::{
2    fmt,
3    mem::{align_of, size_of},
4    ptr::{self, NonNull},
5};
6
7use alloc::alloc::{alloc, alloc_zeroed, dealloc, handle_alloc_error, realloc, Layout};
8
9use super::Core;
10
11
12/// A `Core` implementation that is conceptually a `BitVec` and a `Vec<T>`.
13///
14/// This is the default core as it has quite a few advantages. For one, it does
15/// not waste memory due to padding. The information about whether a slot is
16/// filled or not is stored in a `BitVec` and thus only takes one bit per slot.
17///
18/// Using a `BitVec` has another important advantage: iterating over the
19/// indices of a stable vector (i.e. without touching the actual data) is very
20/// cache-friendly. This is due to the dense packing of information. It's also
21/// possible to very quickly scan the bit vector in order to find filled/empty
22/// slots.
23///
24/// However, this core implementation has disadvantages, too. It manages two
25/// allocations which means that reallocating (growing or shrinking) has to
26/// perform two allocations with the underlying memory allocator. Potentially
27/// more important is the decrease of cache-friendliness when accessing
28/// elements at random. Because in the worst case, this means that each element
29/// access results in two cache-misses instead of only one.
30///
31/// For most use cases, this is a good choice. That's why it's default.
32pub struct BitVecCore<T> {
33    /// This is the memory that stores the actual slots/elements. If a slot is
34    /// empty, the memory at that index is undefined.
35    elem_ptr: NonNull<T>,
36
37    /// Stores whether or not slots are filled (1) or empty (0). Stores one bit
38    /// per slot. Is stored as `usize` instead of `u8` to potentially improve
39    /// performance when finding a hole or counting the elements.
40    bit_ptr: NonNull<usize>,
41
42    /// The capacity: the length of the `elem_ptr` buffer. Corresponse to the
43    /// `cap` of the `Core` definition.
44    cap: usize,
45
46    /// The `len`: corresponse to the `len` of the `Core` definition.
47    len: usize,
48}
49
50const BITS_PER_USIZE: usize = size_of::<usize>() * 8;
51
52impl<T> BitVecCore<T> {
53    /// Deallocates both pointers and sets `cap` to 0.
54    ///
55    /// Note that elements which are still stored in filled slots are **not**
56    /// dropped but simply leaked. So all slots should be empty when calling
57    /// this, unless leaking is intended (see the `Drop` impl below).
58    ///
59    /// # Formal
60    ///
61    /// **Preconditions**:
62    /// - `self.len == 0`
63    unsafe fn dealloc(&mut self) {
64        if self.cap != 0 {
65            if size_of::<T>() != 0 {
66                dealloc(self.elem_ptr.as_ptr() as *mut _, self.old_elem_layout());
67            }
68
69            dealloc(self.bit_ptr.as_ptr() as *mut _, self.old_bit_layout());
70            self.cap = 0;
71        }
72    }
73
74    /// Returns the layout that was used for the last allocation of `elem_ptr`.
75    /// `self.cap` must not be 0 and `T` must not be a ZST, or else this
76    /// method's behavior is undefined.
77    unsafe fn old_elem_layout(&self) -> Layout {
78        Layout::from_size_align_unchecked(
79            // This can't overflow due to being previously allocated.
80            self.cap * size_of::<T>(),
81            align_of::<T>(),
82        )
83    }
84
85    /// Returns the layout that was used for the last allocation of `bit_ptr`.
86    /// `self.cap` must not be 0 or else this method's behavior is undefined.
87    unsafe fn old_bit_layout(&self) -> Layout {
88        Layout::from_size_align_unchecked(
89            size_of::<usize>() * num_usizes_for(self.cap),
90            align_of::<usize>(),
91        )
92    }
93}
94
95impl<T> Core<T> for BitVecCore<T> {
96    fn new() -> Self {
97        Self {
98            elem_ptr: NonNull::dangling(),
99            bit_ptr: NonNull::dangling(),
100            cap: 0,
101            len: 0,
102        }
103    }
104
105    fn len(&self) -> usize {
106        self.len
107    }
108
109    unsafe fn set_len(&mut self, new_len: usize) {
110        debug_assert!(new_len <= self.cap());
111        // Other precondition is too expensive to test, even in debug:
112        // ∀ i in `new_len..self.cap()` ⇒ `self.has_element_at(i) == false`
113
114        self.len = new_len;
115
116        // The formal requirements of this method hold:
117        //
118        // **Invariants**:
119        // - *slot data* -> trivially holds, we do not touch that
120        // - `len ≤ cap` -> that's a precondition
121        //
122        // **Postconditons**:
123        // - `self.len() == new_len`: trivially holds
124    }
125
126    fn cap(&self) -> usize {
127        self.cap
128    }
129
130    #[inline(never)]
131    #[cold]
132    unsafe fn realloc(&mut self, new_cap: usize) {
133        debug_assert!(new_cap >= self.len());
134        debug_assert!(new_cap <= isize::max_value() as usize);
135
136        #[inline(never)]
137        #[cold]
138        fn capacity_overflow() -> ! {
139            panic!("capacity overflow in `stable_vec::BitVecCore::realloc` (attempt \
140                to allocate more than `isize::MAX` bytes");
141        }
142
143        // Handle special case
144        if new_cap == 0 {
145            // Due to preconditions, we know that `self.len == 0` and that in
146            // turn tells us that there aren't any filled slots. So we can just
147            // deallocate the memory.
148            self.dealloc();
149            return;
150        }
151
152
153        // ----- (Re)allocate element memory ---------------------------------
154
155        // We only have to allocate if our size are not zero-sized. Else, we
156        // just don't do anything.
157        if size_of::<T>() != 0 {
158            // Get the new number of bytes for the allocation and create the
159            // memory layout.
160            let size = new_cap.checked_mul(size_of::<T>())
161                .unwrap_or_else(|| capacity_overflow());
162            let new_elem_layout = Layout::from_size_align(size, align_of::<T>())
163                .unwrap_or_else(|_| capacity_overflow());
164
165            // (Re)allocate memory.
166            let ptr = if self.cap == 0 {
167                alloc(new_elem_layout)
168            } else {
169                realloc(self.elem_ptr.as_ptr() as *mut _, self.old_elem_layout(), size)
170            };
171
172            // If the element allocation failed, we quit the program with an
173            // OOM error.
174            if ptr.is_null() {
175                 handle_alloc_error(new_elem_layout);
176            }
177
178            // We already overwrite the pointer here. It is not read/changed
179            // anywhere else in this function.
180            self.elem_ptr = NonNull::new_unchecked(ptr as *mut _);
181        };
182
183
184        // ----- (Re)allocate bitvec memory ----------------------------------
185        {
186            // Get the new number of required bytes for the allocation and
187            // create the memory layout.
188            let size = size_of::<usize>() * num_usizes_for(new_cap);
189            let new_bit_layout = Layout::from_size_align_unchecked(size, align_of::<usize>());
190
191            // (Re)allocate memory.
192            let ptr = if self.cap == 0 {
193                alloc_zeroed(new_bit_layout)
194            } else {
195                realloc(self.bit_ptr.as_ptr() as *mut _, self.old_bit_layout(), size)
196            };
197            let ptr = ptr as *mut usize;
198
199            // If the element allocation failed, we quit the program with an
200            // OOM error.
201            if ptr.is_null() {
202                 handle_alloc_error(new_bit_layout);
203            }
204
205            // If we reallocated, the new memory is not necessarily zeroed, so
206            // we need to do it. TODO: if `alloc` offers a `realloc_zeroed`
207            // in the future, we should use that.
208            if self.cap != 0 {
209                let initialized_usizes = num_usizes_for(self.cap);
210                let new_usizes = num_usizes_for(new_cap);
211                if new_usizes > initialized_usizes {
212                    ptr::write_bytes(
213                        ptr.add(initialized_usizes),
214                        0,
215                        new_usizes - initialized_usizes,
216                    );
217                }
218            }
219
220            self.bit_ptr = NonNull::new_unchecked(ptr as *mut _);
221        }
222
223        self.cap = new_cap;
224
225        // All formal requirements are met now:
226        //
227        // **Invariants**:
228        // - *slot data*: by using `realloc` if `self.cap != 0`, the slot data
229        //   (including deleted-flag) was correctly copied.
230        // - `self.len()`: indeed didn't change
231        //
232        // **Postconditons**:
233        // - `self.cap() == new_cap`: trivially holds due to last line.
234    }
235
236    unsafe fn has_element_at(&self, idx: usize) -> bool {
237        debug_assert!(idx < self.cap());
238
239        // The divisions will be turned into shift and 'and'-instructions.
240        let usize_pos = idx / BITS_PER_USIZE;
241        let bit_pos = idx % BITS_PER_USIZE;
242
243        let block = *self.bit_ptr.as_ptr().add(usize_pos);
244        ((block >> bit_pos) & 0b1) != 0
245    }
246
247    unsafe fn insert_at(&mut self, idx: usize, elem: T) {
248        debug_assert!(idx < self.cap());
249        debug_assert!(self.has_element_at(idx) == false);
250
251        // We first write the value and then update the bitvector to avoid
252        // potential double drops if a random panic appears.
253        ptr::write(self.elem_ptr.as_ptr().add(idx), elem);
254
255        let usize_pos = idx / BITS_PER_USIZE;
256        let bit_pos = idx % BITS_PER_USIZE;
257
258        let mask = 1 << bit_pos;
259        *self.bit_ptr.as_ptr().add(usize_pos) |= mask;
260    }
261
262    unsafe fn remove_at(&mut self, idx: usize) -> T {
263        debug_assert!(idx < self.cap());
264        debug_assert!(self.has_element_at(idx));
265
266        // We first mark the value as deleted and then read the value.
267        // Otherwise, a random panic could lead to a double drop.
268        let usize_pos = idx / BITS_PER_USIZE;
269        let bit_pos = idx % BITS_PER_USIZE;
270
271        let mask = !(1 << bit_pos);
272        *self.bit_ptr.as_ptr().add(usize_pos) &= mask;
273
274        ptr::read(self.elem_ptr.as_ptr().add(idx))
275    }
276
277    unsafe fn get_unchecked(&self, idx: usize) -> &T {
278        debug_assert!(idx < self.cap());
279        debug_assert!(self.has_element_at(idx));
280
281        // The preconditions of this function guarantees us that all
282        // preconditions for `add` are met and that we can safely dereference
283        // the pointer.
284        &*self.elem_ptr.as_ptr().add(idx)
285    }
286
287    unsafe fn get_unchecked_mut(&mut self, idx: usize) -> &mut T {
288        debug_assert!(idx < self.cap());
289        debug_assert!(self.has_element_at(idx));
290
291        // The preconditions of this function guarantees us that all
292        // preconditions for `add` are met and that we can safely dereference
293        // the pointer.
294        &mut *self.elem_ptr.as_ptr().add(idx)
295    }
296
297    fn clear(&mut self) {
298        unsafe {
299            // Remove each element via `remove_at`, which clears the occupancy bit
300            // *before* taking the value out, so a panicking `Drop` can't leave a
301            // slot marked occupied for `BitVecCore::drop` -> `clear` to revisit.
302            for idx in 0..self.len {
303                if self.has_element_at(idx) {
304                    drop(self.remove_at(idx));
305                }
306            }
307            self.len = 0;
308        }
309    }
310
311    // TODO: maybe override `{next|prev}_{hole|index}_from` for performance? In
312    // principle we could scan the bitvector very quickly with specialized
313    // instructions. Needs benchmarking.
314
315    unsafe fn swap(&mut self, a: usize, b: usize) {
316        // Swapping the bits is a bit annoying. To avoid branches we first xor
317        // both previous bits.
318        let a_existed = self.has_element_at(a);
319        let b_existed = self.has_element_at(b);
320
321        // `swap_bit` is 0 if both slots were empty of filled, and 1 if only
322        // only one slot was empty. That also means the mask is 0 if both were
323        // empty/filled before, otherwise the mask has one bit set. We xor with
324        // this mask, meaning that we will flip the corresponding bit.
325        let swap_bit = (a_existed ^ b_existed) as usize;
326
327        // For a
328        let usize_pos = a / BITS_PER_USIZE;
329        let bit_pos = a % BITS_PER_USIZE;
330        let mask = swap_bit << bit_pos;
331        *self.bit_ptr.as_ptr().add(usize_pos) ^= mask;
332
333        // For b
334        let usize_pos = b / BITS_PER_USIZE;
335        let bit_pos = b % BITS_PER_USIZE;
336        let mask = swap_bit << bit_pos;
337        *self.bit_ptr.as_ptr().add(usize_pos) ^= mask;
338
339        // Finally swap the actual elements
340        ptr::swap(
341            self.elem_ptr.as_ptr().add(a),
342            self.elem_ptr.as_ptr().add(b),
343        );
344    }
345}
346
347impl<T> Drop for BitVecCore<T> {
348    fn drop(&mut self) {
349        /// Deallocates the memory of the core in its own `drop`, so that this
350        /// also happens when dropping an element panics.
351        struct DeallocGuard<'a, T>(&'a mut BitVecCore<T>);
352
353        impl<T> Drop for DeallocGuard<'_, T> {
354            fn drop(&mut self) {
355                unsafe {
356                    self.0.len = 0;
357                    self.0.dealloc();
358                }
359            }
360        }
361
362        // Dropping the elements can panic, so the deallocation is done by the
363        // guard: its `drop` runs in both cases. We then simply don't drop the
364        // remaining elements, as we don't want to risk a double-drop process
365        // abort. But while the elements are leaked, we at least dealloc our
366        // own memory.
367        let guard = DeallocGuard(self);
368        guard.0.clear();
369    }
370}
371
372impl<T: Clone> Clone for BitVecCore<T> {
373    fn clone(&self) -> Self {
374        let mut out = Self::new();
375
376        if self.cap != 0 {
377            unsafe {
378                out.realloc(self.cap);
379
380                // The length is set before inserting anything: if a `clone`
381                // below panics, `out` is dropped and it has to be able to see
382                // the elements that were already inserted (otherwise those
383                // would be leaked). All slots of `out` are still empty, so
384                // this is fine.
385                out.set_len(self.len);
386
387                // Clone all elements over. We use `insert_at` instead of
388                // copying the whole bitvec at the end, as it sets the
389                // "filled" bit of each element right away. That way, `out` is
390                // in a valid state at all times, even if `clone` panics.
391                let mut idx = 0;
392                while let Some(next) = self.first_filled_slot_from(idx) {
393                    out.insert_at(next, self.get_unchecked(next).clone());
394                    idx = next + 1;
395                }
396            }
397        }
398
399        out
400    }
401}
402
403// This impl is usually not used. `StableVec` has its own impl which doesn't
404// use this one.
405impl<T> fmt::Debug for BitVecCore<T> {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        f.debug_struct("BitVecCore")
408            .field("len", &self.len())
409            .field("cap", &self.cap())
410            .finish()
411    }
412}
413
414// Implement `Send` and `Sync`. These are not automatically implemented as we
415// use raw pointers. But they are safe to implement (given that `T` implements
416// them). We do not have interior mutability, thus we can implement `Sync`. We
417// also do not share any data with other instance of this type, meaning that
418// `Send` can be implemented.
419unsafe impl<T: Send> Send for BitVecCore<T> {}
420unsafe impl<T: Sync> Sync for BitVecCore<T> {}
421
422#[inline(always)]
423fn num_usizes_for(cap: usize) -> usize {
424    // We need ⌈new_cap / BITS_PER_USIZE⌉ many usizes to store all required
425    // bits. We do rounding up by first adding the (BITS_PER_USIZE - 1).
426    (cap + (BITS_PER_USIZE - 1)) / BITS_PER_USIZE
427}
428
429#[cfg(test)]
430mod tests {
431    use super::*;
432
433    #[test]
434    fn num_usizes() {
435        assert_eq!(num_usizes_for(0), 0);
436        assert_eq!(num_usizes_for(1), 1);
437        assert_eq!(num_usizes_for(2), 1);
438        assert_eq!(num_usizes_for(3), 1);
439
440        #[cfg(target_pointer_width = "64")]
441        {
442            assert_eq!(num_usizes_for(63), 1);
443            assert_eq!(num_usizes_for(64), 1);
444            assert_eq!(num_usizes_for(65), 2);
445            assert_eq!(num_usizes_for(66), 2);
446            assert_eq!(num_usizes_for(66), 2);
447
448            assert_eq!(num_usizes_for(255), 4);
449            assert_eq!(num_usizes_for(256), 4);
450            assert_eq!(num_usizes_for(257), 5);
451            assert_eq!(num_usizes_for(258), 5);
452            assert_eq!(num_usizes_for(259), 5);
453        }
454
455        #[cfg(target_pointer_width = "32")]
456        {
457            assert_eq!(num_usizes_for(31), 1);
458            assert_eq!(num_usizes_for(32), 1);
459            assert_eq!(num_usizes_for(33), 2);
460            assert_eq!(num_usizes_for(34), 2);
461            assert_eq!(num_usizes_for(35), 2);
462
463            assert_eq!(num_usizes_for(127), 4);
464            assert_eq!(num_usizes_for(128), 4);
465            assert_eq!(num_usizes_for(129), 5);
466            assert_eq!(num_usizes_for(130), 5);
467            assert_eq!(num_usizes_for(131), 5);
468        }
469    }
470}