mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(str)!: Str and Ident methods take &GetAllocator (#23781)
Continuation of #23767, #23756, and #23755. Make all methods that construct `Str`s and `Ident`s take `&A where A: GetAllocator<'a>` instead of `&'a Allocator`.
This commit is contained in:
1 parent
838fd638a9
commit
88f4455c72
7 files changed
+153
-22
No files matched your search
@@ -100,7 +100,7 @@ impl<'a> AstBuilder<'a> {
|
||||
/// Allocate an [`Ident`] from an array of string slices.
|
||||
#[inline]
|
||||
pub fn ident_from_strs_array<const N: usize>(self, strings: [&str; N]) -> Ident<'a> {
|
||||
Ident::from_strs_array_in(strings, self.allocator)
|
||||
Ident::from_strs_array_in(strings, &self)
|
||||
}
|
||||
|
||||
/// Convert a [`Cow<'a, str>`] to an [`Ident<'a>`].
|
||||
@@ -111,7 +111,7 @@ impl<'a> AstBuilder<'a> {
|
||||
/// If the `Cow` is owned, allocates the string into arena to generate a new `Ident`.
|
||||
#[inline]
|
||||
pub fn ident_from_cow(self, value: &Cow<'a, str>) -> Ident<'a> {
|
||||
Ident::from_cow_in(value, self.allocator)
|
||||
Ident::from_cow_in(value, &self)
|
||||
}
|
||||
|
||||
/// Allocate a [`Str`] from a string slice.
|
||||
@@ -123,7 +123,7 @@ impl<'a> AstBuilder<'a> {
|
||||
/// Allocate a [`Str`] from an array of string slices.
|
||||
#[inline]
|
||||
pub fn str_from_strs_array<const N: usize>(self, strings: [&str; N]) -> Str<'a> {
|
||||
Str::from_strs_array_in(strings, self.allocator)
|
||||
Str::from_strs_array_in(strings, &self)
|
||||
}
|
||||
|
||||
/// Convert a [`Cow<'a, str>`] to a [`Str<'a>`].
|
||||
@@ -134,7 +134,7 @@ impl<'a> AstBuilder<'a> {
|
||||
/// If the `Cow` is owned, allocates the string into arena to generate a new `Str`.
|
||||
#[inline]
|
||||
pub fn str_from_cow(self, value: &Cow<'a, str>) -> Str<'a> {
|
||||
Str::from_cow_in(value, self.allocator)
|
||||
Str::from_cow_in(value, &self)
|
||||
}
|
||||
|
||||
/// `0`
|
||||
|
||||
@@ -1624,9 +1624,10 @@ mod fix {
|
||||
let mut codegen = fixer.codegen();
|
||||
|
||||
let alloc = Allocator::default();
|
||||
let ast_builder = AstBuilder::new(&alloc);
|
||||
let alloc = &alloc;
|
||||
let ast_builder = AstBuilder::new(alloc);
|
||||
|
||||
let mut vec = deps.elements.clone_in(&alloc);
|
||||
let mut vec = deps.elements.clone_in(alloc);
|
||||
|
||||
for name in names {
|
||||
vec.push(
|
||||
|
||||
@@ -286,7 +286,7 @@ impl<'a> UidGenerator<'a> {
|
||||
let digits = buffer.format(uid_name.postfix);
|
||||
|
||||
if uid_name.underscore_count == 1 {
|
||||
Ident::from_strs_array_in(["_", base, digits], self.allocator)
|
||||
Ident::from_strs_array_in(["_", base, digits], &self.allocator)
|
||||
} else {
|
||||
let mut uid = ArenaStringBuilder::with_capacity_in(
|
||||
uid_name.underscore_count as usize + base.len() + digits.len(),
|
||||
@@ -298,7 +298,7 @@ impl<'a> UidGenerator<'a> {
|
||||
Ident::from(uid)
|
||||
}
|
||||
} else {
|
||||
let uid = Ident::from_strs_array_in(["_", base], self.allocator);
|
||||
let uid = Ident::from_strs_array_in(["_", base], &self.allocator);
|
||||
// SAFETY: String starts with `_`, so trimming off that byte leaves a valid UTF-8 string
|
||||
let base = unsafe { uid.as_str().get_unchecked(1..) };
|
||||
self.names.insert(base, UidName { underscore_count: 1, postfix: 1 });
|
||||
|
||||
@@ -403,7 +403,7 @@ pub fn parse_big_int<'a>(
|
||||
|
||||
let radix = match kind {
|
||||
// Skip parsing with `BigInt` - it's already in decimal form, and underscores are removed
|
||||
Kind::Decimal => return Str::from_cow_in(&s, allocator),
|
||||
Kind::Decimal => return Str::from_cow_in(&s, &allocator),
|
||||
Kind::Binary => 2,
|
||||
Kind::Octal => 8,
|
||||
Kind::Hex => 16,
|
||||
|
||||
@@ -217,11 +217,11 @@ impl<'a> Ident<'a> {
|
||||
// are statically known. See `Allocator::alloc_concat_strs_array`.
|
||||
#[expect(clippy::inline_always)]
|
||||
#[inline(always)]
|
||||
pub fn from_strs_array_in<const N: usize>(
|
||||
pub fn from_strs_array_in<const N: usize, A: GetAllocator<'a>>(
|
||||
strings: [&str; N],
|
||||
allocator: &'a Allocator,
|
||||
allocator: &A,
|
||||
) -> Ident<'a> {
|
||||
Self::from(allocator.alloc_concat_strs_array(strings))
|
||||
Self::from(allocator.allocator().alloc_concat_strs_array(strings))
|
||||
}
|
||||
|
||||
/// Convert a [`Cow<'a, str>`] to an [`Ident<'a>`].
|
||||
@@ -231,10 +231,10 @@ impl<'a> Ident<'a> {
|
||||
///
|
||||
/// If the `Cow` is owned, allocates the string into arena to generate a new `Ident`.
|
||||
#[inline]
|
||||
pub fn from_cow_in(value: &Cow<'a, str>, allocator: &'a Allocator) -> Ident<'a> {
|
||||
pub fn from_cow_in<A: GetAllocator<'a>>(value: &Cow<'a, str>, allocator: &A) -> Ident<'a> {
|
||||
match value {
|
||||
Cow::Borrowed(s) => Ident::from(*s),
|
||||
Cow::Owned(s) => Ident::from_in(s, allocator),
|
||||
Cow::Owned(s) => Ident::from_str_in(s, allocator),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -738,6 +738,71 @@ mod test {
|
||||
assert_eq!(ident, Ident::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[expect(clippy::items_after_statements)]
|
||||
fn ident_from_strs_array_in() {
|
||||
let allocator = Allocator::new();
|
||||
let allocator = &allocator;
|
||||
|
||||
// Pass an actual `Allocator`
|
||||
let ident = Ident::from_strs_array_in(["hello", " ", "world", "!"], &allocator);
|
||||
assert_eq!(ident.as_str(), "hello world!");
|
||||
assert_eq!(ident, Ident::from("hello world!"));
|
||||
|
||||
// Pass a struct which implements `GetAllocator`
|
||||
struct Wrapper<'a>(&'a Allocator);
|
||||
|
||||
impl<'a> GetAllocator<'a> for Wrapper<'a> {
|
||||
fn allocator(&self) -> &'a Allocator {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = Wrapper(allocator);
|
||||
let ident = Ident::from_strs_array_in(["foo", "_", "bar"], &wrapper);
|
||||
assert_eq!(ident.as_str(), "foo_bar");
|
||||
assert_eq!(ident, Ident::from("foo_bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[expect(clippy::items_after_statements)]
|
||||
fn ident_from_cow_in() {
|
||||
let allocator = Allocator::new();
|
||||
let allocator = &allocator;
|
||||
|
||||
// `Cow::Borrowed` references the same string, without allocating in arena
|
||||
let borrowed = "world";
|
||||
let used_before = allocator.used_bytes();
|
||||
let ident = Ident::from_cow_in(&Cow::Borrowed(borrowed), &allocator);
|
||||
assert_eq!(ident.as_str(), "world");
|
||||
assert_eq!(ident, Ident::from("world"));
|
||||
assert_eq!(ident.as_str().as_ptr(), borrowed.as_ptr());
|
||||
assert_eq!(allocator.used_bytes(), used_before);
|
||||
|
||||
// `Cow::Owned` allocates a new string in arena
|
||||
let owned = "owned".to_string();
|
||||
let owned_ptr = owned.as_ptr();
|
||||
let ident = Ident::from_cow_in(&Cow::Owned(owned), &allocator);
|
||||
assert_eq!(ident.as_str(), "owned");
|
||||
assert_eq!(ident, Ident::from("owned"));
|
||||
assert_ne!(ident.as_str().as_ptr(), owned_ptr);
|
||||
assert!(allocator.used_bytes() > used_before);
|
||||
|
||||
// Pass a struct which implements `GetAllocator`
|
||||
struct Wrapper<'a>(&'a Allocator);
|
||||
|
||||
impl<'a> GetAllocator<'a> for Wrapper<'a> {
|
||||
fn allocator(&self) -> &'a Allocator {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = Wrapper(allocator);
|
||||
let ident = Ident::from_cow_in(&Cow::Borrowed("hello"), &wrapper);
|
||||
assert_eq!(ident.as_str(), "hello");
|
||||
assert_eq!(ident, Ident::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arena_ident_hashmap() {
|
||||
let allocator = Allocator::new();
|
||||
|
||||
@@ -84,18 +84,18 @@ impl<'a> Str<'a> {
|
||||
/// use oxc_str::Str;
|
||||
///
|
||||
/// let allocator = Allocator::new();
|
||||
/// let s = Str::from_strs_array_in(["hello", " ", "world", "!"], &allocator);
|
||||
/// let s = Str::from_strs_array_in(["hello", " ", "world", "!"], &&allocator);
|
||||
/// assert_eq!(s.as_str(), "hello world!");
|
||||
/// ```
|
||||
// `#[inline(always)]` because want compiler to be able to optimize where some of `strings`
|
||||
// are statically known. See `Allocator::alloc_concat_strs_array`.
|
||||
#[expect(clippy::inline_always)]
|
||||
#[inline(always)]
|
||||
pub fn from_strs_array_in<const N: usize>(
|
||||
pub fn from_strs_array_in<const N: usize, A: GetAllocator<'a>>(
|
||||
strings: [&str; N],
|
||||
allocator: &'a Allocator,
|
||||
allocator: &A,
|
||||
) -> Str<'a> {
|
||||
Self::from(allocator.alloc_concat_strs_array(strings))
|
||||
Self::from(allocator.allocator().alloc_concat_strs_array(strings))
|
||||
}
|
||||
|
||||
/// Convert a [`Cow<'a, str>`] to a [`Str<'a>`].
|
||||
@@ -105,10 +105,10 @@ impl<'a> Str<'a> {
|
||||
///
|
||||
/// If the `Cow` is owned, allocates the string into arena to generate a new `Str`.
|
||||
#[inline]
|
||||
pub fn from_cow_in(value: &Cow<'a, str>, allocator: &'a Allocator) -> Str<'a> {
|
||||
pub fn from_cow_in<A: GetAllocator<'a>>(value: &Cow<'a, str>, allocator: &A) -> Str<'a> {
|
||||
match value {
|
||||
Cow::Borrowed(s) => Str::from(*s),
|
||||
Cow::Owned(s) => Str::from_in(s, allocator),
|
||||
Cow::Owned(s) => Str::from_str_in(s, allocator),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,4 +368,69 @@ mod test {
|
||||
assert_eq!(s.as_str(), "hello");
|
||||
assert_eq!(s, Str::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[expect(clippy::items_after_statements)]
|
||||
fn str_from_strs_array_in() {
|
||||
let allocator = Allocator::new();
|
||||
let allocator = &allocator;
|
||||
|
||||
// Pass an actual `Allocator`
|
||||
let s = Str::from_strs_array_in(["hello", " ", "world", "!"], &allocator);
|
||||
assert_eq!(s.as_str(), "hello world!");
|
||||
assert_eq!(s, Str::from("hello world!"));
|
||||
|
||||
// Pass a struct which implements `GetAllocator`
|
||||
struct Wrapper<'a>(&'a Allocator);
|
||||
|
||||
impl<'a> GetAllocator<'a> for Wrapper<'a> {
|
||||
fn allocator(&self) -> &'a Allocator {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = Wrapper(allocator);
|
||||
let s = Str::from_strs_array_in(["foo", "_", "bar"], &wrapper);
|
||||
assert_eq!(s.as_str(), "foo_bar");
|
||||
assert_eq!(s, Str::from("foo_bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[expect(clippy::items_after_statements)]
|
||||
fn str_from_cow_in() {
|
||||
let allocator = Allocator::new();
|
||||
let allocator = &allocator;
|
||||
|
||||
// `Cow::Borrowed` references the same string, without allocating in arena
|
||||
let borrowed = "world";
|
||||
let used_before = allocator.used_bytes();
|
||||
let s = Str::from_cow_in(&Cow::Borrowed(borrowed), &allocator);
|
||||
assert_eq!(s.as_str(), "world");
|
||||
assert_eq!(s, Str::from("world"));
|
||||
assert_eq!(s.as_str().as_ptr(), borrowed.as_ptr());
|
||||
assert_eq!(allocator.used_bytes(), used_before);
|
||||
|
||||
// `Cow::Owned` allocates a new string in arena
|
||||
let owned = "owned".to_string();
|
||||
let owned_ptr = owned.as_ptr();
|
||||
let s = Str::from_cow_in(&Cow::Owned(owned), &allocator);
|
||||
assert_eq!(s.as_str(), "owned");
|
||||
assert_eq!(s, Str::from("owned"));
|
||||
assert_ne!(s.as_str().as_ptr(), owned_ptr);
|
||||
assert!(allocator.used_bytes() > used_before);
|
||||
|
||||
// Pass a struct which implements `GetAllocator`
|
||||
struct Wrapper<'a>(&'a Allocator);
|
||||
|
||||
impl<'a> GetAllocator<'a> for Wrapper<'a> {
|
||||
fn allocator(&self) -> &'a Allocator {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = Wrapper(allocator);
|
||||
let s = Str::from_cow_in(&Cow::Borrowed("hello"), &wrapper);
|
||||
assert_eq!(s.as_str(), "hello");
|
||||
assert_eq!(s, Str::from("hello"));
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ impl<'a> UidGenerator<'a> {
|
||||
let digits = buffer.format(uid_name.postfix);
|
||||
|
||||
if uid_name.underscore_count == 1 {
|
||||
Ident::from_strs_array_in(["_", base, digits], self.allocator)
|
||||
Ident::from_strs_array_in(["_", base, digits], &self.allocator)
|
||||
} else {
|
||||
let mut uid = ArenaStringBuilder::with_capacity_in(
|
||||
uid_name.underscore_count as usize + base.len() + digits.len(),
|
||||
@@ -298,7 +298,7 @@ impl<'a> UidGenerator<'a> {
|
||||
Ident::from(uid)
|
||||
}
|
||||
} else {
|
||||
let uid = Ident::from_strs_array_in(["_", base], self.allocator);
|
||||
let uid = Ident::from_strs_array_in(["_", base], &self.allocator);
|
||||
// SAFETY: String starts with `_`, so trimming off that byte leaves a valid UTF-8 string
|
||||
let base = unsafe { uid.as_str().get_unchecked(1..) };
|
||||
self.names.insert(base, UidName { underscore_count: 1, postfix: 1 });
|
||||
|
||||
Reference in new issue
Block a user