From d1bc514de1d2f9443a0344914ccd5ebcae5ab5fc Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:20:10 +0000 Subject: [PATCH] perf(formatter): optimize RegExpLiteral formatting to avoid heap allocations (#17797) --- crates/oxc_formatter/src/write/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/oxc_formatter/src/write/mod.rs b/crates/oxc_formatter/src/write/mod.rs index f003daa5ac8b2..557b5340d02b0 100644 --- a/crates/oxc_formatter/src/write/mod.rs +++ b/crates/oxc_formatter/src/write/mod.rs @@ -1118,12 +1118,19 @@ impl<'a> FormatWrite<'a> for AstNode<'a, BigIntLiteral<'a>> { impl<'a> FormatWrite<'a> for AstNode<'a, RegExpLiteral<'a>> { fn write(&self, f: &mut Formatter<'_, 'a>) { let raw = self.raw().unwrap().as_str(); - let (pattern, flags) = raw.rsplit_once('/').unwrap(); - // TODO: print the flags without allocation. - let mut flags = flags.chars().collect::>(); - flags.sort_unstable(); - let flags = flags.iter().collect::(); - let s = StringBuilder::from_strs_array_in([pattern, "/", &flags], f.context().allocator()); + + let Some((pattern, flags)) = raw.rsplit_once('/') else { + return write!(f, text(raw)); + }; + + // Regex flags are ASCII and limited to at most 8 unique: d, g, i, m, s, u, v, y + debug_assert!(flags.len() <= 8 && flags.is_ascii()); + let mut flags_buf = [0u8; 8]; + let len = flags.len(); + flags_buf[..len].copy_from_slice(flags.as_bytes()); + flags_buf[..len].sort_unstable(); + let flags = str::from_utf8(&flags_buf[..len]).unwrap(); + let s = StringBuilder::from_strs_array_in([pattern, "/", flags], f.context().allocator()); write!(f, text(s.into_str())); } }