Skip to main content

mnemosyne_arena/scratch/aligned_vec/
length.rs

1//! Operations that change an [`AlignedVec`]'s length or content.
2//!
3//! Length-changing operations use the storage module's doubling growth policy,
4//! so scratch reuse remains amortized while quiescent release handles retention.
5//!
6//! Read-only queries, search, sort, and in-place reordering live in
7//! [`super::query`] so each module has a single responsibility.
8
9use super::AlignedVec;
10use super::ScratchElement;
11
12impl<T: ScratchElement> AlignedVec<T> {
13    /// Creates an `AlignedVec` of exactly `len` zero-initialized elements.
14    ///
15    /// Equivalent to `with_capacity(len)` followed by `ensure_len(len)`, but
16    /// expressed as a single constructor. All elements are zero (valid per the
17    /// [`ScratchElement`] invariant).
18    #[inline]
19    #[must_use]
20    pub fn zeroed(len: usize) -> Self {
21        let mut v = Self::with_capacity(len);
22        v.ensure_len(len);
23        v
24    }
25
26    /// Ensures capacity for at least `min_len` elements. Only grows; never
27    /// shrinks. Only zeroes **newly** allocated elements, not existing ones.
28    ///
29    /// Uses geometric (doubling) growth so repeated calls are amortized. A
30    /// provision that bounds the retained size is enforced by quiescent
31    /// [`release`][super::super::pool] trimming, not by narrowing growth
32    /// itself: an exact-growth variant was evaluated and rejected
33    /// (MN-SCRATCH-GROWTH-COST-2026-09-04) because it drops the amortized
34    /// doubling policy this method exists to provide.
35    #[inline]
36    pub fn ensure_len(&mut self, min_len: usize) {
37        if min_len <= self.len {
38            return;
39        }
40        if min_len > self.capacity {
41            self.grow_geometric(min_len);
42        }
43        // SAFETY: capacity >= min_len after grow; `[self.len, min_len)` is
44        // inside the allocation; all-zero is valid for every `ScratchElement`.
45        unsafe { self.extend_with_zeros(min_len) };
46    }
47
48    /// Zeros the range `[self.len, new_len)` and advances `self.len`.
49    ///
50    /// # Safety
51    ///
52    /// `capacity >= new_len` and `new_len >= self.len`. All-zero must be a
53    /// valid bit pattern for `T` (guaranteed by `ScratchElement`).
54    #[inline(always)]
55    unsafe fn extend_with_zeros(&mut self, new_len: usize) {
56        // SAFETY: the caller guarantees capacity and zero-validity.
57        unsafe {
58            core::ptr::write_bytes(self.ptr.add(self.len), 0, new_len - self.len);
59        }
60        self.len = new_len;
61    }
62
63    /// Creates a buffer of exactly `len` elements, every one equal to `value`.
64    ///
65    /// The zero-valued case has a cheaper path in [`zeroed`][Self::zeroed],
66    /// which writes bytes rather than elements.
67    #[inline]
68    #[must_use]
69    pub fn filled(len: usize, value: T) -> Self {
70        let mut buffer = Self::with_capacity(len);
71        buffer.resize(len, value);
72        buffer
73    }
74
75    /// Creates a buffer holding a copy of `slice`.
76    #[inline]
77    #[must_use]
78    pub fn from_slice(slice: &[T]) -> Self {
79        let mut buffer = Self::with_capacity(slice.len());
80        buffer.extend_from_slice(slice);
81        buffer
82    }
83
84    /// Appends one element, growing the allocation if it is full.
85    ///
86    /// Amortized O(1): a growth doubles capacity, so `n` pushes onto an empty
87    /// buffer perform O(log n) reallocations and O(n) element writes.
88    #[inline]
89    pub fn push(&mut self, value: T) {
90        self.reserve(1);
91        // SAFETY: `reserve(1)` leaves `capacity > len`, so `ptr.add(len)` is
92        // inside the allocation and past the initialized prefix `[0, len)`.
93        // `T: Copy` (a `ScratchElement` supertrait), so the write is the whole
94        // initialization and overwrites no live value.
95        unsafe { core::ptr::write(self.ptr.add(self.len), value) };
96        self.len += 1;
97    }
98
99    /// Appends every element of `slice` in one bulk copy.
100    #[inline]
101    pub fn extend_from_slice(&mut self, slice: &[T]) {
102        if slice.is_empty() {
103            return;
104        }
105        self.reserve(slice.len());
106        // SAFETY: `reserve(n)` leaves `capacity >= len + n`, so the destination
107        // range `[len, len + n)` is inside the allocation and past the
108        // initialized prefix. `slice` is a live initialized `[T]`, and it
109        // cannot overlap that range: it is either a distinct allocation or an
110        // initialized region of this one, which the destination excludes.
111        unsafe {
112            core::ptr::copy_nonoverlapping(slice.as_ptr(), self.ptr.add(self.len), slice.len());
113        }
114        self.len += slice.len();
115    }
116
117    /// Sets the length to `new_len`, filling any new elements with `value`.
118    ///
119    /// Shrinking keeps the allocation; `ScratchElement` is `Copy`, so the
120    /// dropped tail needs no destructor run.
121    #[inline]
122    pub fn resize(&mut self, new_len: usize, value: T) {
123        if new_len > self.len {
124            let additional = new_len - self.len;
125            self.reserve(additional);
126            // SAFETY: `reserve(additional)` leaves `capacity >= new_len`. Each
127            // write targets a distinct index in `[len, new_len)`, inside the
128            // allocation and past the initialized prefix; `T: Copy`, so each
129            // write fully initializes its element.
130            unsafe {
131                let base = self.ptr.add(self.len);
132                for offset in 0..additional {
133                    core::ptr::write(base.add(offset), value);
134                }
135            }
136        }
137        self.len = new_len;
138    }
139
140    /// Sets the length to `new_len`, filling any new elements using `f`.
141    ///
142    /// Like [`resize`][Self::resize] but uses a closure for the fill value.
143    /// Shrinking keeps the allocation.
144    #[inline]
145    pub fn resize_with<F: FnMut() -> T>(&mut self, new_len: usize, mut f: F) {
146        if new_len > self.len {
147            let additional = new_len - self.len;
148            self.reserve(additional);
149            // SAFETY: `reserve(additional)` leaves `capacity >= new_len`. Each
150            // write targets a distinct index in `[len, new_len)` inside the
151            // allocation; `T: Copy`, so each write fully initializes its element.
152            unsafe {
153                let base = self.ptr.add(self.len);
154                for offset in 0..additional {
155                    core::ptr::write(base.add(offset), f());
156                }
157            }
158        }
159        self.len = new_len;
160    }
161
162    /// Overwrites every initialized element with the value produced by `f`.
163    ///
164    /// Unlike [`fill`][Self::fill] (which takes a `Copy` value), this version
165    /// accepts a closure so non-`Copy` logic can produce each element.
166    #[inline]
167    pub fn fill_with<F: FnMut() -> T>(&mut self, mut f: F) {
168        // SAFETY: `[0, self.len)` is fully initialized; `T: Copy` makes
169        // overwriting sound.
170        for i in 0..self.len {
171            unsafe { core::ptr::write(self.ptr.add(i), f()) };
172        }
173    }
174
175    /// Sets the length to zero, retaining the underlying allocation for reuse.
176    ///
177    /// Elements are not zeroed; subsequent [`push`][Self::push] or
178    /// [`extend_from_slice`][Self::extend_from_slice] calls will overwrite them
179    /// before exposing them through [`as_slice`][Self::as_slice].
180    #[inline]
181    pub fn clear(&mut self) {
182        self.len = 0;
183    }
184
185    /// Shortens the buffer to `new_len` elements, retaining the allocation.
186    ///
187    /// If `new_len >= self.len()`, this is a no-op.
188    #[inline]
189    pub fn truncate(&mut self, new_len: usize) {
190        if new_len < self.len {
191            self.len = new_len;
192        }
193    }
194
195    /// Appends every element produced by an iterator.
196    ///
197    /// Forwards to [`push`][Self::push] per element; an
198    /// [`extend_from_slice`][Self::extend_from_slice] call is preferred when a
199    /// contiguous source slice is available.
200    #[inline]
201    pub fn extend_from_iter(&mut self, iter: impl IntoIterator<Item = T>) {
202        for value in iter {
203            self.push(value);
204        }
205    }
206}
207
208// ── Drain iterator ───────────────────────────────────────────────────────────
209
210/// A draining iterator returned by [`AlignedVec::drain`].
211///
212/// Yields elements in `[start, end)` by value and, on drop, shifts the
213/// tail left to close the gap.
214pub struct Drain<'a, T: ScratchElement> {
215    pub(super) buf: &'a mut AlignedVec<T>,
216    pub(super) start: usize,
217    pub(super) end: usize,
218    pub(super) current: usize,
219}
220
221impl<T: ScratchElement> Iterator for Drain<'_, T> {
222    type Item = T;
223
224    #[inline]
225    fn next(&mut self) -> Option<T> {
226        if self.current < self.end {
227            // SAFETY: `current < end <= buf.len()` — initialized; T: Copy.
228            let val = unsafe { core::ptr::read(self.buf.ptr.add(self.current)) };
229            self.current += 1;
230            Some(val)
231        } else {
232            None
233        }
234    }
235
236    #[inline]
237    fn size_hint(&self) -> (usize, Option<usize>) {
238        let remaining = self.end - self.current;
239        (remaining, Some(remaining))
240    }
241}
242
243impl<T: ScratchElement> ExactSizeIterator for Drain<'_, T> {}
244
245impl<T: ScratchElement> Drop for Drain<'_, T> {
246    fn drop(&mut self) {
247        let drain_len = self.end - self.start;
248        if drain_len == 0 {
249            return;
250        }
251        let tail_len = self.buf.len - self.end;
252        if tail_len > 0 {
253            // SAFETY: `[end, end + tail_len)` → `[start, start + tail_len)`;
254            // may overlap (when drain_len > 0), so we use `copy` (memmove).
255            unsafe {
256                core::ptr::copy(
257                    self.buf.ptr.add(self.end),
258                    self.buf.ptr.add(self.start),
259                    tail_len,
260                );
261            }
262        }
263        self.buf.len -= drain_len;
264    }
265}