diff --git a/crates/oxc_allocator/src/alloc.rs b/crates/oxc_allocator/src/alloc.rs index 05fc9bc5081c5..e1eb949ee68bf 100644 --- a/crates/oxc_allocator/src/alloc.rs +++ b/crates/oxc_allocator/src/alloc.rs @@ -27,7 +27,6 @@ pub trait Alloc { /// # Panics /// /// Panics if reserving space for `layout` fails. - #[expect(dead_code)] fn alloc(&self, layout: Layout) -> NonNull; /// Deallocate the memory referenced by `ptr`. @@ -36,7 +35,6 @@ pub trait Alloc { /// /// * `ptr` must denote a block of memory currently allocated via this allocator. /// * `layout` must be the same [`Layout`] that block was originally allocated with. - #[expect(dead_code)] unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); /// Grow an existing allocation to new [`Layout`]. @@ -56,7 +54,6 @@ pub trait Alloc { /// * `ptr` must denote a block of memory currently allocated via this allocator. /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. - #[expect(dead_code)] unsafe fn grow(&self, ptr: NonNull, old_layout: Layout, new_layout: Layout) -> NonNull; /// Shrink an existing allocation to new [`Layout`]. @@ -76,7 +73,6 @@ pub trait Alloc { /// * `ptr` must denote a block of memory currently allocated via this allocator. /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. - #[expect(dead_code)] unsafe fn shrink( &self, ptr: NonNull, diff --git a/crates/oxc_allocator/src/vec.rs b/crates/oxc_allocator/src/vec.rs index e2a47b3caffa5..f8b33c51cbe14 100644 --- a/crates/oxc_allocator/src/vec.rs +++ b/crates/oxc_allocator/src/vec.rs @@ -13,13 +13,14 @@ use std::{ slice::SliceIndex, }; -use crate::vec2::Vec as InnerVec; -#[cfg(any(feature = "serialize", test))] -use oxc_estree::{ConcatElement, ESTree, SequenceSerializer, Serializer as ESTreeSerializer}; +use bumpalo::Bump; #[cfg(any(feature = "serialize", test))] use serde::{Serialize, Serializer as SerdeSerializer}; -use crate::{Allocator, Box}; +#[cfg(any(feature = "serialize", test))] +use oxc_estree::{ConcatElement, ESTree, SequenceSerializer, Serializer as ESTreeSerializer}; + +use crate::{Allocator, Box, vec2::Vec as InnerVec}; /// A `Vec` without [`Drop`], which stores its data in the arena allocator. /// @@ -34,7 +35,7 @@ use crate::{Allocator, Box}; /// Static checks make this impossible to do. [`Vec::new_in`] and all other methods which create /// a [`Vec`] will refuse to compile if called with a [`Drop`] type. #[derive(PartialEq, Eq)] -pub struct Vec<'alloc, T>(InnerVec<'alloc, T>); +pub struct Vec<'alloc, T>(InnerVec<'alloc, T, Bump>); /// SAFETY: Not actually safe, but for enabling `Send` for downstream crates. unsafe impl Send for Vec<'_, T> {} @@ -167,7 +168,7 @@ impl<'alloc, T> Vec<'alloc, T> { } impl<'alloc, T> ops::Deref for Vec<'alloc, T> { - type Target = InnerVec<'alloc, T>; + type Target = InnerVec<'alloc, T, Bump>; #[inline] fn deref(&self) -> &Self::Target { @@ -177,13 +178,13 @@ impl<'alloc, T> ops::Deref for Vec<'alloc, T> { impl<'alloc, T> ops::DerefMut for Vec<'alloc, T> { #[inline] - fn deref_mut(&mut self) -> &mut InnerVec<'alloc, T> { + fn deref_mut(&mut self) -> &mut InnerVec<'alloc, T, Bump> { &mut self.0 } } impl<'alloc, T> IntoIterator for Vec<'alloc, T> { - type IntoIter = as IntoIterator>::IntoIter; + type IntoIter = as IntoIterator>::IntoIter; type Item = T; #[inline(always)] diff --git a/crates/oxc_allocator/src/vec2/mod.rs b/crates/oxc_allocator/src/vec2/mod.rs index 973fe64916035..3349c036be129 100644 --- a/crates/oxc_allocator/src/vec2/mod.rs +++ b/crates/oxc_allocator/src/vec2/mod.rs @@ -107,7 +107,6 @@ clippy::undocumented_unsafe_blocks )] -use bumpalo::{Bump, collections::CollectionAllocErr}; use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering; use core::fmt; @@ -125,6 +124,10 @@ use core::slice; // #[cfg(feature = "std")] // use std::io; +use bumpalo::collections::CollectionAllocErr; + +use crate::alloc::Alloc; + mod raw_vec; use raw_vec::RawVec; @@ -295,7 +298,7 @@ macro_rules! vec { (in $alloc:expr; $($x:expr,)*) => (bumpalo::vec![in $alloc; $($x),*]) } -/// A contiguous growable array type, written `Vec<'a, T>` but pronounced 'vector'. +/// A contiguous growable array type, written `Vec<'a, T, A>` but pronounced 'vector'. /// /// # Examples /// @@ -471,7 +474,7 @@ macro_rules! vec { /// `from_raw_parts` to recover the `Vec` and then dropping it. /// /// If a `Vec` *has* allocated memory, then the memory it points to is -/// in the [`Bump`] arena used to construct it, and its +/// in the arena used to construct it, and its /// pointer points to [`len`] initialized, contiguous elements in order (what /// you would see if you coerced it to a slice), followed by [`capacity`] - /// [`len`] logically uninitialized, contiguous elements. @@ -541,15 +544,15 @@ macro_rules! vec { /// [`reserve`]: struct.Vec.html#method.reserve /// [owned slice]: https://doc.rust-lang.org/std/boxed/struct.Box.html #[repr(transparent)] -pub struct Vec<'a, T: 'a> { - buf: RawVec<'a, T>, +pub struct Vec<'a, T: 'a, A: Alloc> { + buf: RawVec<'a, T, A>, } //////////////////////////////////////////////////////////////////////////////// // Inherent methods //////////////////////////////////////////////////////////////////////////////// -impl<'a, T: 'a> Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> { /// Constructs a new, empty `Vec<'a, T>`. /// /// The vector will not allocate until elements are pushed onto it. @@ -564,7 +567,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// let mut vec: Vec = Vec::new_in(&b); /// ``` #[inline] - pub fn new_in(alloc: &'a Bump) -> Vec<'a, T> { + pub fn new_in(alloc: &'a A) -> Vec<'a, T, A> { Vec { buf: RawVec::new_in(alloc) } } @@ -601,7 +604,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// vec.push(11); /// ``` #[inline] - pub fn with_capacity_in(capacity: usize, alloc: &'a Bump) -> Vec<'a, T> { + pub fn with_capacity_in(capacity: usize, alloc: &'a A) -> Vec<'a, T, A> { Vec { buf: RawVec::with_capacity_in(capacity, alloc) } } @@ -617,7 +620,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// let v = Vec::from_iter_in(iter::repeat(7).take(3), &b); /// assert_eq!(v, [7, 7, 7]); /// ``` - pub fn from_iter_in>(iter: I, alloc: &'a Bump) -> Vec<'a, T> { + pub fn from_iter_in>(iter: I, alloc: &'a A) -> Vec<'a, T, A> { let mut v = Vec::new_in(alloc); v.extend(iter); v @@ -684,8 +687,8 @@ impl<'a, T: 'a> Vec<'a, T> { ptr: *mut T, length: usize, capacity: usize, - alloc: &'a Bump, - ) -> Vec<'a, T> { + alloc: &'a A, + ) -> Vec<'a, T, A> { Vec { buf: RawVec::from_raw_parts_in(ptr, length, capacity, alloc) } } @@ -841,7 +844,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// ``` #[inline] #[must_use] - pub fn bump(&self) -> &'a Bump { + pub fn bump(&self) -> &'a A { self.buf.bump() } @@ -1411,14 +1414,14 @@ impl<'a, T: 'a> Vec<'a, T> { // This drop guard will be invoked when predicate or `drop` of element panicked. // It shifts unchecked elements to cover holes and `set_len` to the correct length. // In cases when predicate and `drop` never panick, it will be optimized out. - struct BackshiftOnDrop<'a, 'v, T> { - v: &'v mut Vec<'a, T>, + struct BackshiftOnDrop<'a, 'v, T, A: Alloc> { + v: &'v mut Vec<'a, T, A>, processed_len: usize, deleted_cnt: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, '_, T> { + impl Drop for BackshiftOnDrop<'_, '_, T, A> { fn drop(&mut self) { if self.deleted_cnt > 0 { // SAFETY: Trailing unchecked items must be valid since we never touch them. @@ -1439,10 +1442,10 @@ impl<'a, T: 'a> Vec<'a, T> { let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - fn process_loop( + fn process_loop( original_len: usize, f: &mut F, - g: &mut BackshiftOnDrop<'_, '_, T>, + g: &mut BackshiftOnDrop<'_, '_, T, A>, ) where F: FnMut(&mut T) -> bool, { @@ -1475,10 +1478,10 @@ impl<'a, T: 'a> Vec<'a, T> { } // Stage 1: Nothing was deleted. - process_loop::(original_len, &mut f, &mut g); + process_loop::(original_len, &mut f, &mut g); // Stage 2: Some elements were deleted. - process_loop::(original_len, &mut f, &mut g); + process_loop::(original_len, &mut f, &mut g); // All item are processed. This can be optimized to `set_len` by LLVM. drop(g); @@ -1502,7 +1505,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// assert_eq!(numbers, &[1, 3, 5]); /// assert_eq!(evens, &[2, 4]); /// ``` - pub fn drain_filter<'v, F>(&'v mut self, filter: F) -> DrainFilter<'a, 'v, T, F> + pub fn drain_filter<'v, F>(&'v mut self, filter: F) -> DrainFilter<'a, 'v, T, A, F> where F: FnMut(&mut T) -> bool, { @@ -1722,7 +1725,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// v.drain(..); /// assert_eq!(v, &[]); /// ``` - pub fn drain(&mut self, range: R) -> Drain + pub fn drain(&mut self, range: R) -> Drain where R: RangeBounds, { @@ -1882,7 +1885,7 @@ impl<'a, T> Vec<'a, T> { } */ -impl<'a, T: 'a + Clone> Vec<'a, T> { +impl<'a, T: 'a + Clone, A: Alloc> Vec<'a, T, A> { /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// /// If `new_len` is greater than `len`, the `Vec` is extended by the @@ -1950,7 +1953,7 @@ impl<'a, T: 'a + Clone> Vec<'a, T> { } } -impl<'a, T: 'a + Copy> Vec<'a, T> { +impl<'a, T: 'a + Copy, A: Alloc> Vec<'a, T, A> { /// Helper method to copy all of the items in `other` and append them to the end of `self`. /// /// SAFETY: @@ -2091,7 +2094,7 @@ impl ExtendWith for ExtendElement { } } -impl<'a, T: 'a> Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> { /// Extend the vector by `n` values, using the given generator. fn extend_with>(&mut self, n: usize, mut value: E) { self.reserve(n); @@ -2124,7 +2127,7 @@ impl<'a, T: 'a> Vec<'a, T> { } } -impl<'a, T: 'a + PartialEq> Vec<'a, T> { +impl<'a, T: 'a + PartialEq, A: Alloc> Vec<'a, T, A> { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. /// @@ -2153,9 +2156,9 @@ impl<'a, T: 'a + PartialEq> Vec<'a, T> { // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// -impl<'a, T: 'a + Clone> Clone for Vec<'a, T> { +impl<'a, T: 'a + Clone, A: Alloc> Clone for Vec<'a, T, A> { #[cfg(not(test))] - fn clone(&self) -> Vec<'a, T> { + fn clone(&self) -> Vec<'a, T, A> { let mut v = Vec::with_capacity_in(self.len_usize(), self.buf.bump()); v.extend(self.iter().cloned()); v @@ -2166,21 +2169,21 @@ impl<'a, T: 'a + Clone> Clone for Vec<'a, T> { // `slice::to_vec` function which is only available with cfg(test) // NB see the slice::hack module in slice.rs for more information #[cfg(test)] - fn clone(&self) -> Vec<'a, T> { + fn clone(&self) -> Vec<'a, T, A> { let mut v = Vec::new_in(self.buf.bump()); v.extend(self.iter().cloned()); v } } -impl<'a, T: 'a + Hash> Hash for Vec<'a, T> { +impl<'a, T: 'a + Hash, A: Alloc> Hash for Vec<'a, T, A> { #[inline] fn hash(&self, state: &mut H) { Hash::hash(&**self, state) } } -impl Index for Vec<'_, T> +impl Index for Vec<'_, T, A> where I: ::core::slice::SliceIndex<[T]>, { @@ -2192,7 +2195,7 @@ where } } -impl IndexMut for Vec<'_, T> +impl IndexMut for Vec<'_, T, A> where I: ::core::slice::SliceIndex<[T]>, { @@ -2202,7 +2205,7 @@ where } } -impl<'a, T: 'a> ops::Deref for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> ops::Deref for Vec<'a, T, A> { type Target = [T]; fn deref(&self) -> &[T] { @@ -2214,7 +2217,7 @@ impl<'a, T: 'a> ops::Deref for Vec<'a, T> { } } -impl<'a, T: 'a> ops::DerefMut for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> ops::DerefMut for Vec<'a, T, A> { fn deref_mut(&mut self) -> &mut [T] { unsafe { let ptr = self.buf.ptr(); @@ -2224,7 +2227,7 @@ impl<'a, T: 'a> ops::DerefMut for Vec<'a, T> { } } -impl<'a, T: 'a> IntoIterator for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> IntoIterator for Vec<'a, T, A> { type Item = T; type IntoIter = IntoIter<'a, T>; @@ -2260,7 +2263,7 @@ impl<'a, T: 'a> IntoIterator for Vec<'a, T> { } } -impl<'a, T> IntoIterator for &'a Vec<'_, T> { +impl<'a, T, A: Alloc> IntoIterator for &'a Vec<'_, T, A> { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -2269,7 +2272,7 @@ impl<'a, T> IntoIterator for &'a Vec<'_, T> { } } -impl<'a, T> IntoIterator for &'a mut Vec<'_, T> { +impl<'a, T, A: Alloc> IntoIterator for &'a mut Vec<'_, T, A> { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -2278,7 +2281,7 @@ impl<'a, T> IntoIterator for &'a mut Vec<'_, T> { } } -impl<'a, T: 'a> Extend for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Extend for Vec<'a, T, A> { #[inline] fn extend>(&mut self, iter: I) { let iterator = iter.into_iter(); @@ -2286,7 +2289,7 @@ impl<'a, T: 'a> Extend for Vec<'a, T> { } } -impl<'a, T: 'a> Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply #[track_caller] @@ -2307,7 +2310,7 @@ impl<'a, T: 'a> Vec<'a, T> { // which increases the execution instructions and hits the performance. #[cold] #[inline(never)] - fn reserve_slow(v: &mut Vec, iterator: &impl Iterator) { + fn reserve_slow(v: &mut Vec, iterator: &impl Iterator) { let (lower, _) = iterator.size_hint(); v.reserve(lower.saturating_add(1)); } @@ -2325,7 +2328,7 @@ impl<'a, T: 'a> Vec<'a, T> { } } -impl<'a, T: 'a> Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> { /// Creates a splicing iterator that replaces the specified range in the vector /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as `range`. @@ -2366,7 +2369,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// assert_eq!(u, &[1, 2]); /// ``` #[inline] - pub fn splice(&mut self, range: R, replace_with: I) -> Splice + pub fn splice(&mut self, range: R, replace_with: I) -> Splice where R: RangeBounds, I: IntoIterator, @@ -2381,7 +2384,7 @@ impl<'a, T: 'a> Vec<'a, T> { /// append the entire slice at once. /// /// [`copy_from_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice -impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<'_, T> { +impl<'a, T: 'a + Copy, A: Alloc> Extend<&'a T> for Vec<'_, T, A> { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()) } @@ -2393,9 +2396,13 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<'_, T> { macro_rules! __impl_slice_eq1 { ($Rhs: ty) => { - impl PartialEq<$Rhs> for Vec<'_, T> + __impl_slice_eq1! { $Rhs, } + }; + ($Rhs: ty, $($bounds:tt)*) => { + impl PartialEq<$Rhs> for Vec<'_, T, A> where T: PartialEq, + A: Alloc, { #[inline] fn eq(&self, other: &$Rhs) -> bool { @@ -2405,15 +2412,16 @@ macro_rules! __impl_slice_eq1 { }; } -__impl_slice_eq1! { Vec<'_, U> } +__impl_slice_eq1! { Vec<'_, U, A2>, A2: Alloc } __impl_slice_eq1! { &[U] } __impl_slice_eq1! { &mut [U] } macro_rules! __impl_slice_eq1_array { ($Rhs: ty) => { - impl PartialEq<$Rhs> for Vec<'_, T> + impl PartialEq<$Rhs> for Vec<'_, T, A> where T: PartialEq, + A: Alloc, { #[inline] fn eq(&self, other: &$Rhs) -> bool { @@ -2428,19 +2436,19 @@ __impl_slice_eq1_array! { &[U; N] } __impl_slice_eq1_array! { &mut [U; N] } /// Implements comparison of vectors, lexicographically. -impl<'a, T: 'a + PartialOrd> PartialOrd for Vec<'a, T> { +impl<'a, T: 'a + PartialOrd, A: Alloc, A2: Alloc> PartialOrd> for Vec<'a, T, A> { #[inline] - fn partial_cmp(&self, other: &Vec<'a, T>) -> Option { + fn partial_cmp(&self, other: &Vec<'a, T, A2>) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } -impl<'a, T: 'a + Eq> Eq for Vec<'a, T> {} +impl<'a, T: 'a + Eq, A: Alloc> Eq for Vec<'a, T, A> {} /// Implements ordering of vectors, lexicographically. -impl<'a, T: 'a + Ord> Ord for Vec<'a, T> { +impl<'a, T: 'a + Ord, A: Alloc> Ord for Vec<'a, T, A> { #[inline] - fn cmp(&self, other: &Vec<'a, T>) -> Ordering { + fn cmp(&self, other: &Vec<'a, T, A>) -> Ordering { Ord::cmp(&**self, &**other) } } @@ -2449,31 +2457,31 @@ impl<'a, T: 'a + Ord> Ord for Vec<'a, T> { // Misc //////////////////////////////////////////////////////////////////////////////// -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Vec<'a, T> { +impl<'a, T: 'a + fmt::Debug, A: Alloc> fmt::Debug for Vec<'a, T, A> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl<'a, T: 'a> AsRef> for Vec<'a, T> { - fn as_ref(&self) -> &Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> AsRef> for Vec<'a, T, A> { + fn as_ref(&self) -> &Vec<'a, T, A> { self } } -impl<'a, T: 'a> AsMut> for Vec<'a, T> { - fn as_mut(&mut self) -> &mut Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> AsMut> for Vec<'a, T, A> { + fn as_mut(&mut self) -> &mut Vec<'a, T, A> { self } } -impl<'a, T: 'a> AsRef<[T]> for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> AsRef<[T]> for Vec<'a, T, A> { fn as_ref(&self) -> &[T] { self } } -impl<'a, T: 'a> AsMut<[T]> for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> AsMut<[T]> for Vec<'a, T, A> { fn as_mut(&mut self) -> &mut [T] { self } @@ -2481,21 +2489,21 @@ impl<'a, T: 'a> AsMut<[T]> for Vec<'a, T> { /* #[cfg(feature = "boxed")] -impl<'a, T: 'a> From> for crate::boxed::Box<'a, [T]> { - fn from(v: Vec<'a, T>) -> crate::boxed::Box<'a, [T]> { +impl<'a, T: 'a, A: Alloc> From> for crate::boxed::Box<'a, [T]> { + fn from(v: Vec<'a, T, A>) -> crate::boxed::Box<'a, [T]> { v.into_boxed_slice() } } */ -impl<'a, T: 'a> Borrow<[T]> for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> Borrow<[T]> for Vec<'a, T, A> { #[inline] fn borrow(&self) -> &[T] { &self[..] } } -impl<'a, T: 'a> BorrowMut<[T]> for Vec<'a, T> { +impl<'a, T: 'a, A: Alloc> BorrowMut<[T]> for Vec<'a, T, A> { #[inline] fn borrow_mut(&mut self) -> &mut [T] { &mut self[..] @@ -2506,14 +2514,14 @@ impl<'a, T: 'a> BorrowMut<[T]> for Vec<'a, T> { // Clone-on-write //////////////////////////////////////////////////////////////////////////////// -// impl<'a, 'v, T: Clone> From> for Cow<'v, [T]> { -// fn from(v: Vec<'a, T>) -> Cow<'v, [T]> { +// impl<'a, 'v, T: Clone, A: Alloc> From> for Cow<'v, [T]> { +// fn from(v: Vec<'a, T, A>) -> Cow<'v, [T]> { // Cow::Owned(v) // } // } -// impl<'a, 'v, T: Clone> From<&'v Vec<'a, T>> for Cow<'v, [T]> { -// fn from(v: &'v Vec<'a, T>) -> Cow<'v, [T]> { +// impl<'a, 'v, T: Clone, A: Alloc> From<&'v Vec<'a, T, A>> for Cow<'v, [T]> { +// fn from(v: &'v Vec<'a, T, A>) -> Cow<'v, [T]> { // Cow::Borrowed(v.as_slice()) // } // } @@ -2661,26 +2669,27 @@ impl Drop for IntoIter<'_, T> { /// A draining iterator for `Vec<'a, T>`. /// /// This `struct` is created by the [`Vec::drain`] method. -pub struct Drain<'a, 's, T: 'a + 's> { +pub struct Drain<'a, 's, T: 'a + 's, A: Alloc> { /// Index of tail to preserve tail_start: usize, /// Length of tail tail_len: usize, /// Current remaining range to remove iter: slice::Iter<'s, T>, - vec: NonNull>, + vec: NonNull>, } -impl<'a, 's, T: 'a + 's + fmt::Debug> fmt::Debug for Drain<'a, 's, T> { +impl<'a, 's, T: 'a + 's + fmt::Debug, A: Alloc> fmt::Debug for Drain<'a, 's, T, A> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } -unsafe impl Sync for Drain<'_, '_, T> {} -unsafe impl Send for Drain<'_, '_, T> {} +// TODO: Should these also require `A: Send` / `A: Sync` bounds? +unsafe impl Sync for Drain<'_, '_, T, A> {} +unsafe impl Send for Drain<'_, '_, T, A> {} -impl Iterator for Drain<'_, '_, T> { +impl Iterator for Drain<'_, '_, T, A> { type Item = T; #[inline] @@ -2693,14 +2702,14 @@ impl Iterator for Drain<'_, '_, T> { } } -impl DoubleEndedIterator for Drain<'_, '_, T> { +impl DoubleEndedIterator for Drain<'_, '_, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) } } -impl Drop for Drain<'_, '_, T> { +impl Drop for Drain<'_, '_, T, A> { fn drop(&mut self) { // exhaust self first self.for_each(drop); @@ -2722,21 +2731,21 @@ impl Drop for Drain<'_, '_, T> { } } -impl ExactSizeIterator for Drain<'_, '_, T> {} +impl ExactSizeIterator for Drain<'_, '_, T, A> {} -impl FusedIterator for Drain<'_, '_, T> {} +impl FusedIterator for Drain<'_, '_, T, A> {} /// A splicing iterator for `Vec`. /// /// This struct is created by the [`Vec::splice`] method. See its /// documentation for more information. #[derive(Debug)] -pub struct Splice<'a, 'd, I: Iterator + 'a + 'd> { - drain: Drain<'a, 'd, I::Item>, +pub struct Splice<'a, 'd, I: Iterator + 'a + 'd, A: Alloc> { + drain: Drain<'a, 'd, I::Item, A>, replace_with: I, } -impl Iterator for Splice<'_, '_, I> { +impl Iterator for Splice<'_, '_, I, A> { type Item = I::Item; fn next(&mut self) -> Option { @@ -2748,15 +2757,15 @@ impl Iterator for Splice<'_, '_, I> { } } -impl DoubleEndedIterator for Splice<'_, '_, I> { +impl DoubleEndedIterator for Splice<'_, '_, I, A> { fn next_back(&mut self) -> Option { self.drain.next_back() } } -impl ExactSizeIterator for Splice<'_, '_, I> {} +impl ExactSizeIterator for Splice<'_, '_, I, A> {} -impl Drop for Splice<'_, '_, I> { +impl Drop for Splice<'_, '_, I, A> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -2799,7 +2808,7 @@ impl Drop for Splice<'_, '_, I> { } /// Private helper methods for `Splice::drop` -impl Drain<'_, '_, T> { +impl Drain<'_, '_, T, A> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. @@ -2843,18 +2852,18 @@ impl Drain<'_, '_, T> { /// An iterator produced by calling [`Vec::drain_filter`]. #[derive(Debug)] -pub struct DrainFilter<'a: 'v, 'v, T: 'a + 'v, F> +pub struct DrainFilter<'a: 'v, 'v, T: 'a + 'v, A: Alloc, F> where F: FnMut(&mut T) -> bool, { - vec: &'v mut Vec<'a, T>, + vec: &'v mut Vec<'a, T, A>, idx: usize, del: usize, old_len: usize, pred: F, } -impl Iterator for DrainFilter<'_, '_, T, F> +impl Iterator for DrainFilter<'_, '_, T, A, F> where F: FnMut(&mut T) -> bool, { @@ -2888,7 +2897,7 @@ where } } -impl Drop for DrainFilter<'_, '_, T, F> +impl Drop for DrainFilter<'_, '_, T, A, F> where F: FnMut(&mut T) -> bool, { diff --git a/crates/oxc_allocator/src/vec2/raw_vec.rs b/crates/oxc_allocator/src/vec2/raw_vec.rs index 17d82bbaeca43..fe0d8f1524b12 100644 --- a/crates/oxc_allocator/src/vec2/raw_vec.rs +++ b/crates/oxc_allocator/src/vec2/raw_vec.rs @@ -23,16 +23,16 @@ #![allow(unstable_name_collisions)] #![allow(dead_code)] -use allocator_api2::alloc::{AllocError, Allocator, handle_alloc_error}; -use bumpalo::Bump; - -pub use core::alloc::Layout; +use core::alloc::Layout; use core::cmp; use core::mem; use core::ptr::{self, NonNull}; +use allocator_api2::alloc::AllocError; use bumpalo::collections::CollectionAllocErr::{self, AllocErr, CapacityOverflow}; +use crate::alloc::Alloc; + // use boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating @@ -64,17 +64,17 @@ use bumpalo::collections::CollectionAllocErr::{self, AllocErr, CapacityOverflow} /// this type. #[allow(missing_debug_implementations)] #[repr(C)] -pub struct RawVec<'a, T> { +pub struct RawVec<'a, T, A: Alloc> { ptr: NonNull, len: u32, cap: u32, - alloc: &'a Bump, + alloc: &'a A, } -impl<'a, T> RawVec<'a, T> { +impl<'a, T, A: Alloc> RawVec<'a, T, A> { /// Like `new` but parameterized over the choice of allocator for /// the returned RawVec. - pub fn new_in(alloc: &'a Bump) -> Self { + pub fn new_in(alloc: &'a A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. RawVec { ptr: NonNull::dangling(), alloc, cap: 0, len: 0 } } @@ -82,7 +82,7 @@ impl<'a, T> RawVec<'a, T> { /// Like `with_capacity` but parameterized over the choice of /// allocator for the returned RawVec. #[inline] - pub fn with_capacity_in(cap: usize, alloc: &'a Bump) -> Self { + pub fn with_capacity_in(cap: usize, alloc: &'a A) -> Self { unsafe { let elem_size = mem::size_of::(); @@ -95,11 +95,7 @@ impl<'a, T> RawVec<'a, T> { } else { let align = mem::align_of::(); let layout = Layout::from_size_align(alloc_size, align).unwrap(); - let result = alloc.allocate(layout); - match result { - Ok(ptr) => ptr.cast(), - Err(_) => handle_alloc_error(layout), - } + alloc.alloc(layout).cast::() }; // `cap as u32` is safe because `alloc_guard` ensures that `cap` @@ -122,7 +118,7 @@ impl<'a, T> RawVec<'a, T> { /// /// If all these values came from a `Vec` created in allocator `a`, then these requirements /// are guaranteed to be fulfilled. - pub unsafe fn from_raw_parts_in(ptr: *mut T, len: usize, cap: usize, alloc: &'a Bump) -> Self { + pub unsafe fn from_raw_parts_in(ptr: *mut T, len: usize, cap: usize, alloc: &'a A) -> Self { // SAFETY: Caller guarantees `ptr` was allocated, which implies it's not null let ptr = unsafe { NonNull::new_unchecked(ptr) }; @@ -189,7 +185,7 @@ impl<'a, T> RawVec<'a, T> { } /// Returns a shared reference to the allocator backing this RawVec. - pub fn bump(&self) -> &'a Bump { + pub fn bump(&self) -> &'a A { self.alloc } @@ -465,7 +461,7 @@ impl<'a, T> RawVec<'a, T> { // handle_reserve behind a call, while making sure that this function is likely to be // inlined as just a comparison and a call if the comparison fails. #[cold] - fn do_reserve_and_handle(slf: &mut RawVec, len: u32, additional: usize) { + fn do_reserve_and_handle(slf: &mut RawVec, len: u32, additional: usize) { if let Err(err) = slf.grow_amortized(len, additional) { handle_error(err); } @@ -598,10 +594,8 @@ impl<'a, T> RawVec<'a, T> { let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); let new_layout = Layout::from_size_align_unchecked(new_size, align); - match self.alloc.shrink(self.ptr.cast(), old_layout, new_layout) { - Ok(p) => self.ptr = p.cast(), - Err(_) => handle_alloc_error(new_layout), - } + self.ptr = + self.alloc.shrink(self.ptr.cast::(), old_layout, new_layout).cast::(); } self.cap = amount; } @@ -633,7 +627,7 @@ impl<'a, T> RawVec<'a, T> { } */ -impl RawVec<'_, T> { +impl RawVec<'_, T, A> { #[inline] fn needs_to_grow(&self, len: u32, additional: usize) -> bool { // `self.cap().wrapping_sub(len) as usize` is safe because @@ -730,40 +724,40 @@ impl RawVec<'_, T> { // Given a new layout, completes the grow operation. #[inline] - fn finish_grow(&self, new_layout: Layout) -> Result, CollectionAllocErr> { + fn finish_grow(&self, new_layout: Layout) -> Result, CollectionAllocErr> { alloc_guard(new_layout.size())?; - let res = match self.current_layout() { + let new_ptr = match self.current_layout() { Some(layout) => unsafe { // Marking this function as `#[cold]` and `#[inline(never)]` because grow method is // relatively expensive and we want to avoid inlining it into the caller. #[cold] #[inline(never)] - unsafe fn grow( - alloc: &Bump, + unsafe fn grow( + alloc: &A, ptr: NonNull, old_layout: Layout, new_layout: Layout, - ) -> Result, AllocError> { + ) -> NonNull { alloc.grow(ptr.cast(), old_layout, new_layout) } debug_assert!(new_layout.align() == layout.align()); grow(self.alloc, self.ptr, layout, new_layout) }, - None => self.alloc.allocate(new_layout), + None => self.alloc.alloc(new_layout), }; - res.map_err(|_| AllocErr) + Ok(new_ptr) } } -impl RawVec<'_, T> { +impl RawVec<'_, T, A> { /// Frees the memory owned by the RawVec *without* trying to Drop its contents. pub unsafe fn dealloc_buffer(&mut self) { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.alloc.deallocate(self.ptr.cast(), layout); + self.alloc.dealloc(self.ptr.cast(), layout); } } } @@ -820,20 +814,22 @@ fn handle_error(error: CollectionAllocErr) -> ! { #[cfg(test)] mod tests { + use bumpalo::Bump; + use super::*; #[test] fn reserve_does_not_overallocate() { let arena = Bump::new(); { - let mut v: RawVec = RawVec::new_in(&arena); + let mut v: RawVec = RawVec::new_in(&arena); // First `reserve` allocates like `reserve_exact` v.reserve(0, 9); assert_eq!(9, v.capacity_u32()); } { - let mut v: RawVec = RawVec::new_in(&arena); + let mut v: RawVec = RawVec::new_in(&arena); v.reserve(0, 7); assert_eq!(7, v.capacity_u32()); // 97 if more than double of 7, so `reserve` should work @@ -843,7 +839,7 @@ mod tests { } { - let mut v: RawVec = RawVec::new_in(&arena); + let mut v: RawVec = RawVec::new_in(&arena); v.reserve(0, 12); assert_eq!(12, v.capacity_u32()); v.reserve(12, 3);