Skip to main content

vortex_buffer/
buffer_mut.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use core::mem::MaybeUninit;
5use std::alloc::Layout;
6use std::any::type_name;
7use std::cmp::max;
8use std::fmt::Debug;
9use std::fmt::Formatter;
10use std::ops::Deref;
11use std::ops::DerefMut;
12
13use itertools::Itertools;
14use vortex_error::VortexExpect;
15use vortex_error::vortex_panic;
16
17use crate::Alignment;
18use crate::Allocation;
19use crate::Buffer;
20use crate::BufferAllocatorRef;
21use crate::ByteBufferMut;
22use crate::debug::TruncatedDebug;
23use crate::trusted_len::TrustedLen;
24
25/// A mutable buffer that maintains a runtime-defined alignment through resizing operations.
26///
27/// Zero-sized element types are rejected at compile time when constructing a buffer.
28///
29/// ```compile_fail
30/// use vortex_buffer::BufferMut;
31/// let _ = BufferMut::<()>::empty();
32/// ```
33///
34/// ```compile_fail
35/// use vortex_buffer::BufferMut;
36/// let _ = BufferMut::<()>::zeroed(3);
37/// ```
38pub struct BufferMut<T> {
39    /// The owned allocation, including any bytes before `ptr` used for alignment.
40    pub(crate) allocation: Allocation,
41    /// The first element, aligned to `alignment`; it may dangle for an empty buffer.
42    pub(crate) ptr: std::ptr::NonNull<T>,
43    /// The number of initialized `T` values starting at `ptr`.
44    pub(crate) length: usize,
45    /// The number of `T` values that fit from `ptr`.
46    pub(crate) capacity: usize,
47    /// The minimum alignment maintained for `ptr` across reallocations.
48    pub(crate) alignment: Alignment,
49    /// Marks the buffer as logically owning values of `T` despite storing an erased allocation.
50    pub(crate) _marker: std::marker::PhantomData<T>,
51}
52
53// SAFETY: BufferMut uniquely owns its allocation and only exposes T across threads.
54unsafe impl<T: Send> Send for BufferMut<T> {}
55// SAFETY: shared access to BufferMut only exposes shared access to T.
56unsafe impl<T: Sync> Sync for BufferMut<T> {}
57
58impl<T> BufferMut<T> {
59    /// Create a new `BufferMut` with the requested alignment and capacity.
60    pub fn with_capacity(capacity: usize) -> Self {
61        Self::with_capacity_in(capacity, BufferAllocatorRef::statically_allocated())
62    }
63
64    /// Create a new `BufferMut` with the requested capacity and allocator.
65    pub fn with_capacity_in(capacity: usize, allocator: BufferAllocatorRef) -> Self {
66        Self::with_capacity_aligned_in(capacity, Alignment::of::<T>(), allocator)
67    }
68
69    /// Create a new `BufferMut` with the requested alignment and capacity.
70    ///
71    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
72    /// `alignment`. Use [`with_capacity_preferred_aligned`] to control the over-alignment.
73    ///
74    /// [`with_capacity_preferred_aligned`]: Self::with_capacity_preferred_aligned
75    pub fn with_capacity_aligned(capacity: usize, alignment: Alignment) -> Self {
76        Self::with_capacity_aligned_in(
77            capacity,
78            alignment,
79            BufferAllocatorRef::statically_allocated(),
80        )
81    }
82
83    /// Create a new `BufferMut` with the requested alignment, capacity, and allocator.
84    pub fn with_capacity_aligned_in(
85        capacity: usize,
86        alignment: Alignment,
87        allocator: BufferAllocatorRef,
88    ) -> Self {
89        Self::with_capacity_preferred_aligned_in(
90            capacity,
91            alignment,
92            Some(Alignment::DEFAULT_ALIGNMENT),
93            allocator,
94        )
95    }
96
97    /// Create a new `BufferMut` with the requested alignment and capacity.
98    ///
99    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
100    /// of `alignment` and `preferred_alignment`.
101    pub fn with_capacity_preferred_aligned(
102        capacity: usize,
103        alignment: Alignment,
104        preferred_alignment: Option<Alignment>,
105    ) -> Self {
106        Self::with_capacity_preferred_aligned_in(
107            capacity,
108            alignment,
109            preferred_alignment,
110            BufferAllocatorRef::statically_allocated(),
111        )
112    }
113
114    /// Create a new allocator-backed `BufferMut` with a requested and preferred alignment.
115    pub fn with_capacity_preferred_aligned_in(
116        capacity: usize,
117        alignment: Alignment,
118        preferred_alignment: Option<Alignment>,
119        allocator: BufferAllocatorRef,
120    ) -> Self {
121        const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
122        let actual = max(
123            alignment,
124            preferred_alignment.unwrap_or(Alignment::of::<u8>()),
125        );
126
127        if !alignment.is_aligned_to(Alignment::of::<T>()) {
128            vortex_panic!(
129                "Alignment {} must align to the scalar type's alignment {}",
130                alignment,
131                align_of::<T>()
132            );
133        }
134
135        let size = capacity
136            .checked_mul(size_of::<T>())
137            .vortex_expect("buffer capacity overflow");
138        let layout = if size == 0 {
139            Layout::from_size_align(0, actual.as_usize())
140                .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
141        } else {
142            let allocation_size = size
143                .checked_add(actual.as_usize())
144                .vortex_expect("buffer capacity overflow");
145            Layout::from_size_align(allocation_size, 1).unwrap_or_else(|_| {
146                vortex_panic!("buffer capacity exceeds maximum allocation size")
147            })
148        };
149        let allocation = Allocation::allocate(layout, allocator);
150        let offset = allocation.ptr().as_ptr().align_offset(actual.as_usize());
151        // SAFETY: the allocation includes enough padding to reach this aligned pointer.
152        let ptr = unsafe { allocation.ptr().add(offset).cast() };
153        let capacity = (allocation.size() - offset) / size_of::<T>();
154        Self {
155            allocation,
156            ptr,
157            length: 0,
158            capacity,
159            alignment,
160            _marker: Default::default(),
161        }
162    }
163
164    /// Create a new zeroed `BufferMut`.
165    pub fn zeroed(len: usize) -> Self {
166        Self::zeroed_in(len, BufferAllocatorRef::statically_allocated())
167    }
168
169    /// Create a new zeroed `BufferMut` with the requested allocator.
170    pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
171        Self::zeroed_aligned_in(len, Alignment::of::<T>(), allocator)
172    }
173
174    /// Create a new zeroed `BufferMut` with the requested alignment.
175    ///
176    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
177    /// `alignment`. Use [`zeroed_preferred_aligned`] to control the over-alignment.
178    ///
179    /// [`zeroed_preferred_aligned`]: Self::zeroed_preferred_aligned
180    pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
181        Self::zeroed_aligned_in(len, alignment, BufferAllocatorRef::statically_allocated())
182    }
183
184    /// Create a zeroed `BufferMut` with an alignment and allocator.
185    pub fn zeroed_aligned_in(
186        len: usize,
187        alignment: Alignment,
188        allocator: BufferAllocatorRef,
189    ) -> Self {
190        Self::zeroed_preferred_aligned_in(
191            len,
192            alignment,
193            Some(Alignment::DEFAULT_ALIGNMENT),
194            allocator,
195        )
196    }
197
198    /// Create a new zeroed `BufferMut` with the requested alignment.
199    ///
200    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
201    /// of `alignment` and `preferred_alignment`.
202    pub fn zeroed_preferred_aligned(
203        len: usize,
204        alignment: Alignment,
205        preferred_alignment: Option<Alignment>,
206    ) -> Self {
207        Self::zeroed_preferred_aligned_in(
208            len,
209            alignment,
210            preferred_alignment,
211            BufferAllocatorRef::statically_allocated(),
212        )
213    }
214
215    /// Create a zeroed allocator-backed buffer with a requested and preferred alignment.
216    pub fn zeroed_preferred_aligned_in(
217        len: usize,
218        alignment: Alignment,
219        preferred_alignment: Option<Alignment>,
220        allocator: BufferAllocatorRef,
221    ) -> Self {
222        const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
223        let preferred_alignment = preferred_alignment.unwrap_or(Alignment::of::<u8>());
224        let actual_alignment = max(preferred_alignment, alignment);
225        let size = len
226            .checked_mul(size_of::<T>())
227            .vortex_expect("buffer length overflow");
228        let layout = if size == 0 {
229            Layout::from_size_align(0, actual_alignment.as_usize())
230                .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
231        } else {
232            let allocation_size = size
233                .checked_add(actual_alignment.as_usize())
234                .vortex_expect("buffer length overflow");
235            Layout::from_size_align(allocation_size, 1)
236                .unwrap_or_else(|_| vortex_panic!("buffer length exceeds maximum allocation size"))
237        };
238        let allocation = Allocation::allocate_zeroed(layout, allocator);
239        let offset = allocation
240            .ptr()
241            .as_ptr()
242            .align_offset(actual_alignment.as_usize());
243        // SAFETY: the allocation includes enough padding to reach this aligned pointer.
244        let ptr = unsafe { allocation.ptr().add(offset).cast() };
245        let capacity = (allocation.size() - offset) / size_of::<T>();
246        Self {
247            allocation,
248            ptr,
249            length: len,
250            capacity,
251            alignment,
252            _marker: Default::default(),
253        }
254    }
255
256    /// Create a new empty `BufferMut` with the provided alignment.
257    pub fn empty() -> Self {
258        Self::empty_aligned(Alignment::of::<T>())
259    }
260
261    /// Create a new empty `BufferMut` with the provided alignment.
262    ///
263    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
264    /// `alignment`. Use [`empty_preferred_aligned`] to control the over-alignment.
265    ///
266    /// [`empty_preferred_aligned`]: Self::empty_preferred_aligned
267    pub fn empty_aligned(alignment: Alignment) -> Self {
268        Self::empty_aligned_in(alignment, BufferAllocatorRef::statically_allocated())
269    }
270
271    /// Create an empty `BufferMut` with an alignment and allocator.
272    pub fn empty_aligned_in(alignment: Alignment, allocator: BufferAllocatorRef) -> Self {
273        Self::with_capacity_aligned_in(0, alignment, allocator)
274    }
275
276    /// Create a new empty `BufferMut` with the provided alignment.
277    ///
278    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
279    /// of `alignment` and `preferred_alignment`.
280    pub fn empty_preferred_aligned(
281        alignment: Alignment,
282        preferred_alignment: Option<Alignment>,
283    ) -> Self {
284        BufferMut::with_capacity_preferred_aligned_in(
285            0,
286            alignment,
287            preferred_alignment,
288            BufferAllocatorRef::statically_allocated(),
289        )
290    }
291
292    /// Create a new full `BufferMut` with the given value.
293    pub fn full(item: T, len: usize) -> Self
294    where
295        T: Copy,
296    {
297        Self::full_in(item, len, BufferAllocatorRef::statically_allocated())
298    }
299
300    /// Create a full `BufferMut` with the given value and allocator.
301    pub fn full_in(item: T, len: usize, allocator: BufferAllocatorRef) -> Self
302    where
303        T: Copy,
304    {
305        let mut buffer = BufferMut::<T>::with_capacity_in(len, allocator);
306        buffer.push_n(item, len);
307        buffer
308    }
309
310    /// Create a mutable scalar buffer by copying the contents of the slice.
311    pub fn copy_from(other: impl AsRef<[T]>) -> Self {
312        Self::copy_from_in(other, BufferAllocatorRef::statically_allocated())
313    }
314
315    /// Create a mutable scalar buffer by copying with the given allocator.
316    pub fn copy_from_in(other: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self {
317        Self::copy_from_aligned_in(other, Alignment::of::<T>(), allocator)
318    }
319
320    /// Create a mutable scalar buffer with the alignment by copying the contents of the slice.
321    ///
322    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
323    /// `alignment`. Use [`copy_from_preferred_aligned`] to control the over-alignment.
324    ///
325    /// [`copy_from_preferred_aligned`]: Self::copy_from_preferred_aligned
326    ///
327    /// ## Panics
328    ///
329    /// Panics when the requested alignment isn't itself aligned to type T.
330    pub fn copy_from_aligned(other: impl AsRef<[T]>, alignment: Alignment) -> Self {
331        Self::copy_from_aligned_in(other, alignment, BufferAllocatorRef::statically_allocated())
332    }
333
334    /// Copy values into a mutable buffer with the given alignment and allocator.
335    pub fn copy_from_aligned_in(
336        other: impl AsRef<[T]>,
337        alignment: Alignment,
338        allocator: BufferAllocatorRef,
339    ) -> Self {
340        Self::copy_from_preferred_aligned_in(
341            other,
342            alignment,
343            Some(Alignment::DEFAULT_ALIGNMENT),
344            allocator,
345        )
346    }
347
348    /// Create a mutable scalar buffer with the alignment by copying the contents of the slice.
349    ///
350    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
351    /// of `alignment` and `preferred_alignment`.
352    ///
353    /// ## Panics
354    ///
355    /// Panics when the requested alignment isn't itself aligned to type T.
356    pub fn copy_from_preferred_aligned(
357        other: impl AsRef<[T]>,
358        alignment: Alignment,
359        preferred_alignment: Option<Alignment>,
360    ) -> Self {
361        Self::copy_from_preferred_aligned_in(
362            other,
363            alignment,
364            preferred_alignment,
365            BufferAllocatorRef::statically_allocated(),
366        )
367    }
368
369    /// Copy values with the given allocator, requested alignment, and preferred alignment.
370    pub fn copy_from_preferred_aligned_in(
371        other: impl AsRef<[T]>,
372        alignment: Alignment,
373        preferred_alignment: Option<Alignment>,
374        allocator: BufferAllocatorRef,
375    ) -> Self {
376        if !alignment.is_aligned_to(Alignment::of::<T>()) {
377            vortex_panic!("Given alignment is not aligned to type T")
378        }
379        let other = other.as_ref();
380        let mut buffer = Self::with_capacity_preferred_aligned_in(
381            other.len(),
382            alignment,
383            preferred_alignment,
384            allocator,
385        );
386        buffer.extend_from_slice(other);
387        debug_assert_eq!(buffer.alignment(), alignment);
388        buffer
389    }
390
391    /// Get the alignment of the buffer.
392    #[allow(clippy::inline_always)]
393    #[inline(always)]
394    pub fn alignment(&self) -> Alignment {
395        self.alignment
396    }
397
398    /// Returns the allocator that owns this buffer.
399    pub fn allocator(&self) -> &BufferAllocatorRef {
400        self.allocation.allocator()
401    }
402
403    /// Returns the length of the buffer.
404    #[allow(clippy::inline_always)]
405    #[inline(always)]
406    pub fn len(&self) -> usize {
407        self.length
408    }
409
410    /// Returns whether the buffer is empty.
411    #[allow(clippy::inline_always)]
412    #[inline(always)]
413    pub fn is_empty(&self) -> bool {
414        self.length == 0
415    }
416
417    /// Returns the capacity of the buffer.
418    #[inline]
419    pub fn capacity(&self) -> usize {
420        self.capacity
421    }
422
423    /// Returns a raw pointer to the buffer's data.
424    #[allow(clippy::inline_always)]
425    #[inline(always)]
426    pub fn as_ptr(&self) -> *const T {
427        self.ptr.as_ptr()
428    }
429
430    /// Returns a mutable raw pointer to the buffer's data.
431    #[allow(clippy::inline_always)]
432    #[inline(always)]
433    pub fn as_mut_ptr(&mut self) -> *mut T {
434        self.ptr.as_ptr()
435    }
436
437    /// Returns a slice over the buffer of elements of type T.
438    #[inline]
439    pub fn as_slice(&self) -> &[T] {
440        // SAFETY: ptr is in the live allocation and construction checks its alignment.
441        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.length) }
442    }
443
444    /// Returns a slice over the buffer of elements of type T.
445    #[inline]
446    pub fn as_mut_slice(&mut self) -> &mut [T] {
447        // SAFETY: BufferMut uniquely owns the allocation and the initialized range is in bounds.
448        unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.length) }
449    }
450
451    /// Clear the buffer, retaining any existing capacity.
452    #[inline]
453    pub fn clear(&mut self) {
454        self.length = 0;
455    }
456
457    /// Shortens the buffer, keeping the first `len` bytes and dropping the
458    /// rest.
459    ///
460    /// If `len` is greater than the buffer's current length, this has no
461    /// effect.
462    ///
463    /// Existing underlying capacity is preserved.
464    #[inline]
465    pub fn truncate(&mut self, len: usize) {
466        if len <= self.len() {
467            // SAFETY: Shrinking the buffer cannot expose uninitialized bytes.
468            unsafe { self.set_len(len) };
469        }
470    }
471
472    /// Reserves capacity for at least `additional` more elements to be inserted in the buffer.
473    #[inline]
474    pub fn reserve(&mut self, additional: usize) {
475        if additional <= self.capacity() - self.length {
476            // We can fit the additional bytes in the remaining capacity. Nothing to do.
477            return;
478        }
479
480        // Otherwise, reserve additional + alignment bytes in case we need to realign the buffer.
481        self.reserve_allocate(additional);
482    }
483
484    /// A separate function so we can inline the reserve call's fast path.
485    fn reserve_allocate(&mut self, additional: usize) {
486        let required = self
487            .length
488            .checked_add(additional)
489            .vortex_expect("buffer capacity overflow");
490        let required_size = required
491            .checked_mul(size_of::<T>())
492            .vortex_expect("buffer capacity overflow");
493        let alignment = self.alignment;
494        let current_size = self
495            .capacity
496            .checked_mul(size_of::<T>())
497            .vortex_expect("buffer capacity overflow");
498        let logical_size = required_size
499            .max(current_size.saturating_mul(2))
500            .max(Alignment::DEFAULT_ALIGNMENT.as_usize());
501        let allocation_size = logical_size
502            .checked_add(alignment.as_usize())
503            .vortex_expect("buffer capacity overflow");
504        let allocation_alignment = if self.allocation.size() == 0 {
505            1
506        } else {
507            self.allocation.alignment()
508        };
509        let layout = Layout::from_size_align(allocation_size, allocation_alignment)
510            .unwrap_or_else(|_| vortex_panic!("buffer capacity exceeds maximum allocation size"));
511
512        let old_offset = self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
513        let new_offset = if self.allocation.allocator().is_statically_allocated() {
514            let allocation =
515                Allocation::allocate(layout, BufferAllocatorRef::statically_allocated());
516            let new_offset = allocation.ptr().as_ptr().align_offset(alignment.as_usize());
517            // SAFETY: both allocations have room for the initialized elements and do not overlap.
518            unsafe {
519                std::ptr::copy_nonoverlapping(
520                    self.ptr.cast::<u8>().as_ptr(),
521                    allocation.ptr().as_ptr().add(new_offset),
522                    self.length * size_of::<T>(),
523                );
524            }
525            self.allocation = allocation;
526            new_offset
527        } else {
528            self.allocation.grow(layout);
529            let new_offset = self
530                .allocation
531                .ptr()
532                .as_ptr()
533                .align_offset(alignment.as_usize());
534            if new_offset != old_offset {
535                // SAFETY: grow preserved the initialized elements at old_offset. The new allocation
536                // has room for the requested elements plus alignment padding, and copy permits
537                // overlap.
538                unsafe {
539                    std::ptr::copy(
540                        self.allocation.ptr().as_ptr().add(old_offset),
541                        self.allocation.ptr().as_ptr().add(new_offset),
542                        self.length * size_of::<T>(),
543                    );
544                }
545            }
546            new_offset
547        };
548        // SAFETY: new_offset was computed within the allocation for alignment.
549        self.ptr = unsafe { self.allocation.ptr().add(new_offset).cast() };
550        self.capacity = logical_size / size_of::<T>();
551    }
552
553    /// Returns the spare capacity of the buffer as a slice of `MaybeUninit<T>`.
554    /// Has identical semantics to [`Vec::spare_capacity_mut`].
555    ///
556    /// The returned slice can be used to fill the buffer with data (e.g. by
557    /// reading from a file) before marking the data as initialized using the
558    /// [`set_len`] method.
559    ///
560    /// Note that the returned slice may be larger than the capacity requested at
561    /// construction, since the underlying allocation can be rounded up (e.g. to
562    /// satisfy alignment requirements).
563    ///
564    /// [`set_len`]: BufferMut::set_len
565    /// [`Vec::spare_capacity_mut`]: Vec::spare_capacity_mut
566    ///
567    /// # Examples
568    ///
569    /// ```
570    /// use vortex_buffer::BufferMut;
571    ///
572    /// // Allocate vector big enough for 10 elements.
573    /// let mut b = BufferMut::<u64>::with_capacity(10);
574    ///
575    /// // Fill in the first 3 elements.
576    /// let uninit = b.spare_capacity_mut();
577    /// uninit[0].write(0);
578    /// uninit[1].write(1);
579    /// uninit[2].write(2);
580    ///
581    /// // Mark the first 3 elements of the vector as being initialized.
582    /// unsafe {
583    ///     b.set_len(3);
584    /// }
585    ///
586    /// assert_eq!(b.as_slice(), &[0u64, 1, 2]);
587    /// ```
588    #[inline]
589    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
590        // SAFETY: offset + length is within the allocation and points at spare capacity.
591        let dst = unsafe { self.as_mut_ptr().add(self.length) }.cast::<MaybeUninit<T>>();
592        unsafe { std::slice::from_raw_parts_mut(dst, self.capacity() - self.length) }
593    }
594
595    /// Sets the length of the buffer.
596    ///
597    /// # Safety
598    ///
599    /// - `new_len` must be less than or equal to [`capacity()`].
600    /// - The elements at `old_len..new_len` must be initialized.
601    ///
602    /// [`capacity()`]: Self::capacity
603    #[inline]
604    pub unsafe fn set_len(&mut self, len: usize) {
605        debug_assert!(len <= self.capacity());
606        self.length = len;
607    }
608
609    /// Appends a scalar to the buffer.
610    #[inline]
611    pub fn push(&mut self, value: T) {
612        self.reserve(1);
613        unsafe { self.push_unchecked(value) }
614    }
615
616    /// Appends a scalar to the buffer without checking for sufficient capacity.
617    ///
618    /// ## Safety
619    ///
620    /// The caller must ensure there is sufficient capacity in the array.
621    #[inline]
622    pub unsafe fn push_unchecked(&mut self, item: T) {
623        // SAFETY: the caller ensures we have sufficient capacity
624        unsafe {
625            let dst = self.as_mut_ptr().add(self.length);
626            dst.write(item);
627        }
628        self.length += 1;
629    }
630
631    /// Appends n scalars to the buffer.
632    ///
633    /// This function is slightly more optimized than `extend(iter::repeat_n(item, b))`.
634    #[inline]
635    pub fn push_n(&mut self, item: T, n: usize)
636    where
637        T: Copy,
638    {
639        self.reserve(n);
640        unsafe { self.push_n_unchecked(item, n) }
641    }
642
643    /// Appends n scalars to the buffer.
644    ///
645    /// ## Safety
646    ///
647    /// The caller must ensure there is sufficient capacity in the array.
648    #[inline]
649    pub unsafe fn push_n_unchecked(&mut self, item: T, n: usize)
650    where
651        T: Copy,
652    {
653        // SAFETY: the caller guarantees enough spare capacity.
654        let mut dst = unsafe { self.as_mut_ptr().add(self.length) };
655        // SAFETY: we checked the capacity in the reserve call
656        unsafe {
657            let end = dst.add(n);
658            while dst < end {
659                dst.write(item);
660                dst = dst.add(1);
661            }
662        }
663        self.length += n;
664    }
665
666    /// Appends a slice of type `T`, growing the internal buffer as needed.
667    ///
668    /// # Example:
669    ///
670    /// ```
671    /// # use vortex_buffer::BufferMut;
672    ///
673    /// let mut builder = BufferMut::<u16>::with_capacity(10);
674    /// builder.extend_from_slice(&[42, 44, 46]);
675    ///
676    /// assert_eq!(builder.len(), 3);
677    /// ```
678    #[inline]
679    pub fn extend_from_slice(&mut self, slice: &[T]) {
680        self.reserve(slice.len());
681        // SAFETY: reserve made the destination valid and non-overlapping for slice.len() values.
682        unsafe {
683            std::ptr::copy_nonoverlapping(
684                slice.as_ptr(),
685                self.as_mut_ptr().add(self.length),
686                slice.len(),
687            );
688        }
689        self.length += slice.len();
690    }
691
692    /// Return the [`ByteBufferMut`] for this [`BufferMut`].
693    pub fn into_byte_buffer(self) -> ByteBufferMut {
694        let capacity = self
695            .capacity
696            .checked_mul(size_of::<T>())
697            .vortex_expect("buffer capacity overflow");
698        ByteBufferMut {
699            allocation: self.allocation,
700            ptr: self.ptr.cast(),
701            length: self.length * size_of::<T>(),
702            capacity,
703            alignment: self.alignment,
704            _marker: Default::default(),
705        }
706    }
707
708    /// Freeze the `BufferMut` into a `Buffer`.
709    pub fn freeze(self) -> Buffer<T> {
710        let offset = self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
711        Buffer::from_allocation(self.allocation, offset, self.length, self.alignment)
712    }
713
714    /// Map each element of the buffer with a closure.
715    pub fn map_each_in_place<R, F>(self, mut f: F) -> BufferMut<R>
716    where
717        T: Copy,
718        F: FnMut(T) -> R,
719    {
720        assert_eq!(
721            size_of::<T>(),
722            size_of::<R>(),
723            "Size of T and R do not match"
724        );
725        // SAFETY: we have checked that `size_of::<T>` == `size_of::<R>`.
726        let mut buf: BufferMut<R> = unsafe { std::mem::transmute(self) };
727        buf.iter_mut()
728            .for_each(|item| *item = f(unsafe { std::mem::transmute_copy(item) }));
729        buf
730    }
731
732    /// Return a `BufferMut<T>` with the same data as this one with the given alignment.
733    ///
734    /// If the data is already properly aligned, this is a metadata-only operation.
735    ///
736    /// If the data is not aligned, we copy it into a new allocation.
737    pub fn aligned(self, alignment: Alignment) -> Self {
738        if self.as_ptr().align_offset(alignment.as_usize()) == 0 {
739            Self { alignment, ..self }
740        } else {
741            let capacity = self.capacity();
742            let allocator = self.allocation.allocator().clone();
743            let mut aligned = Self::with_capacity_aligned_in(capacity, alignment, allocator);
744            aligned.extend_from_slice(&self);
745            aligned.capacity = capacity;
746            aligned
747        }
748    }
749
750    /// Transmute a `Buffer<T>` into a `Buffer<U>`.
751    ///
752    /// # Safety
753    ///
754    /// The caller must ensure that all possible bit representations of type `T` are valid when
755    /// interpreted as type `U`.
756    /// See [`std::mem::transmute`] for more details.
757    ///
758    /// # Panics
759    ///
760    /// Panics if the type `U` does not have the same size and alignment as `T`.
761    pub unsafe fn transmute<U>(self) -> BufferMut<U> {
762        assert_eq!(size_of::<T>(), size_of::<U>(), "Buffer type size mismatch");
763        assert_eq!(
764            align_of::<T>(),
765            align_of::<U>(),
766            "Buffer type alignment mismatch"
767        );
768
769        BufferMut {
770            allocation: self.allocation,
771            ptr: self.ptr.cast(),
772            length: self.length,
773            capacity: self.capacity,
774            alignment: self.alignment,
775            _marker: std::marker::PhantomData,
776        }
777    }
778}
779
780impl<T> Clone for BufferMut<T> {
781    fn clone(&self) -> Self {
782        let mut buffer = BufferMut::<T>::with_capacity_aligned_in(
783            self.capacity(),
784            self.alignment,
785            self.allocation.allocator().clone(),
786        );
787        buffer.extend_from_slice(self.as_slice());
788        buffer
789    }
790}
791
792impl<T: PartialEq> PartialEq for BufferMut<T> {
793    fn eq(&self, other: &Self) -> bool {
794        self.as_slice() == other.as_slice()
795    }
796}
797
798impl<T: Eq> Eq for BufferMut<T> {}
799
800impl<T: Debug> Debug for BufferMut<T> {
801    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
802        f.debug_struct(&format!("BufferMut<{}>", type_name::<T>()))
803            .field("length", &self.length)
804            .field("alignment", &self.alignment)
805            .field("as_slice", &TruncatedDebug(self.as_slice()))
806            .finish()
807    }
808}
809
810impl<T> Default for BufferMut<T> {
811    fn default() -> Self {
812        Self::empty()
813    }
814}
815
816impl<T> Deref for BufferMut<T> {
817    type Target = [T];
818
819    #[inline]
820    fn deref(&self) -> &Self::Target {
821        self.as_slice()
822    }
823}
824
825impl<T> DerefMut for BufferMut<T> {
826    #[inline]
827    fn deref_mut(&mut self) -> &mut Self::Target {
828        self.as_mut_slice()
829    }
830}
831
832impl<T> AsRef<[T]> for BufferMut<T> {
833    #[inline]
834    fn as_ref(&self) -> &[T] {
835        self.as_slice()
836    }
837}
838
839impl<T> AsMut<[T]> for BufferMut<T> {
840    #[inline]
841    fn as_mut(&mut self) -> &mut [T] {
842        self.as_mut_slice()
843    }
844}
845
846impl<T> BufferMut<T> {
847    /// A helper method for the two [`Extend`] implementations.
848    ///
849    /// We use the lower bound hint on the iterator to manually write data, and then we continue to
850    /// push items normally past the lower bound.
851    fn extend_iter(&mut self, mut iter: impl Iterator<Item = T>) {
852        // Since we do not know the length of the iterator, we can only guess how much memory we
853        // need to reserve. Note that these hints may be inaccurate.
854        let (lower_bound, _) = iter.size_hint();
855
856        // We choose not to use the optional upper bound size hint to match the standard library.
857
858        self.reserve(lower_bound);
859
860        let unwritten = self.capacity() - self.len();
861
862        // We store `begin` in the case that the lower bound hint is incorrect.
863        let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
864        let mut dst: *mut T = begin.cast_mut();
865
866        // As a first step, we manually iterate the iterator up to the known capacity.
867        for _ in 0..unwritten {
868            let Some(item) = iter.next() else {
869                // The lower bound hint may be incorrect.
870                break;
871            };
872
873            // SAFETY: We have reserved enough capacity to hold this item, and `dst` is a pointer
874            // derived from a valid reference to byte data.
875            unsafe { dst.write(item) };
876
877            // Note: We used to have `dst.add(iteration).write(item)`, here. However this was much
878            // slower than just incrementing `dst`.
879            // SAFETY: The offsets fits in `isize`, and because we were able to reserve the memory
880            // we know that `add` will not overflow.
881            unsafe { dst = dst.add(1) };
882        }
883
884        // SAFETY: `dst` was derived from `begin`, which were both valid references to byte data,
885        // and since the only operation that `dst` has is `add`, we know that `dst >= begin`.
886        let items_written = unsafe { dst.offset_from_unsigned(begin) };
887        let length = self.len() + items_written;
888
889        // SAFETY: We have written valid items between the old length and the new length.
890        unsafe { self.set_len(length) };
891
892        // Finally, since the iterator will have arbitrarily more items to yield, we push the
893        // remaining items normally.
894        iter.for_each(|item| self.push(item));
895    }
896
897    /// Extends the `BufferMut` with an iterator with `TrustedLen`.
898    ///
899    /// The caller guarantees that the iterator will have a trusted upper bound, which allows the
900    /// implementation to reserve all of the memory needed up front.
901    pub fn extend_trusted<I: TrustedLen<Item = T>>(&mut self, iter: I) {
902        let (_, upper_bound) = iter.size_hint();
903        self.reserve(
904            upper_bound
905                .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
906        );
907
908        let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
909        let mut dst: *mut T = begin.cast_mut();
910
911        iter.for_each(|item| {
912            // SAFETY: We have reserved enough capacity to hold this item, and `dst` is a pointer
913            // derived from a valid reference to byte data.
914            unsafe { dst.write(item) };
915
916            // Note: We used to have `dst.add(iteration).write(item)`, here. However this was much
917            // slower than just incrementing `dst`.
918            // SAFETY: The offset fits in `isize`, and because we were able to reserve the memory
919            // we know that `add` will not overflow.
920            unsafe { dst = dst.add(1) };
921        });
922
923        // SAFETY: `dst` starts at `begin` and advances by one for each item, so both pointers refer
924        // to the same allocation and `dst` is at or after `begin`.
925        let items_written = unsafe { dst.offset_from_unsigned(begin) };
926        let length = self.len() + items_written;
927
928        // SAFETY: We have written valid items between the old length and the new length.
929        unsafe { self.set_len(length) };
930    }
931
932    /// Creates a `BufferMut` from an iterator with a trusted length.
933    ///
934    /// Internally, this calls [`extend_trusted()`](Self::extend_trusted).
935    pub fn from_trusted_len_iter<I>(iter: I) -> Self
936    where
937        I: TrustedLen<Item = T>,
938    {
939        let (_, upper_bound) = iter.size_hint();
940        let mut buffer = Self::with_capacity(
941            upper_bound
942                .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
943        );
944
945        buffer.extend_trusted(iter);
946        buffer
947    }
948
949    /// Like [`extend_trusted()`](Self::extend_trusted), but the iterator yields `Result<T, E>`
950    /// and the extension short-circuits on the first `Err`.
951    ///
952    /// On error, items written before the failure remain in the buffer.
953    pub fn try_extend_trusted<E, I>(&mut self, iter: I) -> Result<(), E>
954    where
955        I: TrustedLen<Item = Result<T, E>>,
956    {
957        iter.process_results(|values| self.extend_trusted(values))
958    }
959
960    /// Like [`from_trusted_len_iter()`](Self::from_trusted_len_iter), but the iterator yields
961    /// `Result<T, E>` and construction short-circuits on the first `Err`.
962    pub fn try_from_trusted_len_iter<E, I>(iter: I) -> Result<Self, E>
963    where
964        I: TrustedLen<Item = Result<T, E>>,
965    {
966        iter.process_results(|values| Self::from_trusted_len_iter(values))
967    }
968}
969
970impl<T> Extend<T> for BufferMut<T> {
971    #[inline]
972    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
973        self.extend_iter(iter.into_iter())
974    }
975}
976
977impl<'a, T> Extend<&'a T> for BufferMut<T>
978where
979    T: Copy + 'a,
980{
981    #[inline]
982    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
983        self.extend_iter(iter.into_iter().copied())
984    }
985}
986
987impl<T> FromIterator<T> for BufferMut<T> {
988    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
989        let iter = iter.into_iter();
990        let mut buffer = Self::with_capacity(iter.size_hint().0);
991        buffer.extend(iter);
992        buffer
993    }
994}
995
996#[cfg(test)]
997mod test {
998    use crate::Alignment;
999    use crate::BufferMut;
1000    use crate::buffer_mut;
1001
1002    #[test]
1003    fn capacity() {
1004        let mut n = 57;
1005        let mut buf = BufferMut::<i32>::with_capacity_aligned(n, Alignment::new(1024));
1006        assert!(buf.capacity() >= 57);
1007
1008        while n > 0 {
1009            buf.push(0);
1010            assert!(buf.capacity() >= n);
1011            n -= 1
1012        }
1013
1014        assert_eq!(buf.alignment(), Alignment::new(1024));
1015    }
1016
1017    #[test]
1018    fn growth_preserves_alignment_and_values() {
1019        let alignment = Alignment::new(4096);
1020        let mut buffer = BufferMut::<u64>::with_capacity_aligned(1, alignment);
1021
1022        for value in 0..10_000 {
1023            buffer.push(value);
1024            assert!(alignment.is_offset_aligned(buffer.as_ptr().addr()));
1025        }
1026
1027        assert_eq!(buffer.as_slice(), (0..10_000).collect::<Vec<_>>());
1028    }
1029
1030    #[test]
1031    fn growth_seeds_and_doubles_logical_capacity() {
1032        let alignment = Alignment::new(64);
1033        let mut buffer = BufferMut::<u8>::empty_aligned(alignment);
1034
1035        buffer.push(0);
1036        let capacity = buffer.capacity();
1037        assert_eq!(capacity, Alignment::DEFAULT_ALIGNMENT.as_usize());
1038
1039        buffer.reserve(capacity);
1040        assert_eq!(buffer.capacity(), capacity * 2);
1041    }
1042
1043    #[test]
1044    fn static_growth_copies_live_data() {
1045        let mut buffer = BufferMut::<u32>::with_capacity(1);
1046        let capacity = buffer.capacity();
1047        buffer.extend(std::iter::repeat_n(7, capacity));
1048        let old_ptr = buffer.as_ptr();
1049
1050        buffer.push(u32::MAX);
1051
1052        assert_ne!(buffer.as_ptr(), old_ptr);
1053        assert_eq!(&buffer[..capacity], vec![7; capacity]);
1054        assert_eq!(buffer[capacity], u32::MAX);
1055    }
1056
1057    #[test]
1058    fn raising_logical_alignment_preserves_capacity() {
1059        let buffer =
1060            BufferMut::<u8>::with_capacity_preferred_aligned(1, Alignment::of::<u8>(), None);
1061        let capacity = buffer.capacity();
1062
1063        let mut buffer = buffer.aligned(Alignment::new(2));
1064
1065        assert_eq!(buffer.capacity(), capacity);
1066        buffer.extend(0..100);
1067        assert!(Alignment::new(2).is_ptr_aligned(buffer.as_ptr()));
1068        assert_eq!(buffer.as_slice(), (0..100).collect::<Vec<_>>());
1069    }
1070
1071    #[test]
1072    fn from_iter() {
1073        let buf = BufferMut::from_iter([0, 10, 20, 30]);
1074        assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1075    }
1076
1077    #[test]
1078    fn try_from_trusted_len_iter_ok() {
1079        let buf = BufferMut::<i32>::try_from_trusted_len_iter(
1080            [0, 10, 20, 30].iter().map(|&v| Ok::<_, ()>(v)),
1081        )
1082        .unwrap();
1083        assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1084    }
1085
1086    #[test]
1087    fn try_from_trusted_len_iter_err() {
1088        let result: Result<BufferMut<i32>, &'static str> = BufferMut::try_from_trusted_len_iter(
1089            [0, 10, 20, 30]
1090                .iter()
1091                .map(|&v| if v == 20 { Err("bad") } else { Ok(v) }),
1092        );
1093        assert_eq!(result.err(), Some("bad"));
1094    }
1095
1096    #[test]
1097    fn try_extend_trusted_retains_values_before_error() {
1098        let mut buf = BufferMut::from_iter([0, 10]);
1099        let result = buf.try_extend_trusted([Ok(20), Err("bad"), Ok(30)].into_iter());
1100
1101        assert_eq!(result, Err("bad"));
1102        assert_eq!(buf.as_slice(), &[0, 10, 20]);
1103    }
1104
1105    #[test]
1106    fn extend() {
1107        let mut buf = BufferMut::empty();
1108        buf.extend([0i32, 10, 20, 30]);
1109        buf.extend([40, 50, 60]);
1110        assert_eq!(buf.as_slice(), &[0, 10, 20, 30, 40, 50, 60]);
1111    }
1112
1113    #[test]
1114    fn push() {
1115        let mut buf = BufferMut::empty();
1116        buf.push(1);
1117        buf.push(2);
1118        buf.push(3);
1119        assert_eq!(buf.as_slice(), &[1, 2, 3]);
1120    }
1121
1122    #[test]
1123    fn push_n() {
1124        let mut buf = BufferMut::empty();
1125        buf.push_n(0, 100);
1126        assert_eq!(buf.as_slice(), &[0; 100]);
1127    }
1128
1129    #[test]
1130    fn as_mut() {
1131        let mut buf = buffer_mut![0, 1, 2];
1132        // Uses DerefMut
1133        buf[1] = 0;
1134        // Uses as_mut
1135        buf.as_mut()[2] = 0;
1136        assert_eq!(buf.as_slice(), &[0, 0, 0]);
1137    }
1138
1139    #[test]
1140    fn map_each() {
1141        let buf = buffer_mut![0i32, 1, 2];
1142        // Add one, and cast to an unsigned u32 in the same closure
1143        let buf = buf.map_each_in_place(|i| (i + 1) as u32);
1144        assert_eq!(buf.as_slice(), &[1u32, 2, 3]);
1145    }
1146
1147    #[test]
1148    fn buffer_mut_zeroed() {
1149        const LEN: usize = 17;
1150
1151        let mut buf = BufferMut::<u32>::zeroed(LEN);
1152
1153        assert_eq!(
1154            buf.as_ptr().align_offset(Alignment::of::<u32>().as_usize()),
1155            0
1156        );
1157        assert_eq!(buf.as_slice(), &[0; LEN]);
1158
1159        buf[3] = 7;
1160        assert_eq!(buf.as_slice()[3], 7);
1161    }
1162
1163    #[test]
1164    fn buffer_mut_zeroed_aligned() {
1165        const LEN: usize = 17;
1166        let alignment = Alignment::new(64);
1167
1168        let mut buf = BufferMut::<u32>::zeroed_aligned(LEN, alignment);
1169
1170        assert_eq!(buf.as_ptr().align_offset(alignment.as_usize()), 0);
1171        assert_eq!(buf.as_slice(), &[0; LEN]);
1172
1173        buf[3] = 7;
1174        assert_eq!(buf.as_slice()[3], 7);
1175    }
1176}