@@ -37,6 +37,26 @@ pub struct MangleOptions {
3737
3838type Slot = usize ;
3939
40+ /// Enum to handle both owned and borrowed allocators. This is not `Cow` because that type
41+ /// requires `ToOwned`/`Clone`, which is not implemented for `Allocator`. Although this does
42+ /// incur some pointer indirect on each reference to the allocator, it allows the API to be
43+ /// more ergonomic by either accepting an existing allocator, or allowing an internal one to
44+ /// be created and used temporarily automatically.
45+ enum TempAllocator < ' t > {
46+ Owned ( Allocator ) ,
47+ Borrowed ( & ' t Allocator ) ,
48+ }
49+
50+ impl TempAllocator < ' _ > {
51+ /// Get a reference to the allocator, regardless of whether it's owned or borrowed
52+ fn as_ref ( & self ) -> & Allocator {
53+ match self {
54+ TempAllocator :: Owned ( allocator) => allocator,
55+ TempAllocator :: Borrowed ( allocator) => allocator,
56+ }
57+ }
58+ }
59+
4060/// # Name Mangler / Symbol Minification
4161///
4262/// ## Example
@@ -155,17 +175,80 @@ type Slot = usize;
155175/// - slot 1: `top_level_b`, `foo_a`, `bar_a`
156176/// - slot 2: `foo`
157177/// - slot 3: `bar`
158- #[ derive( Default ) ]
159- pub struct Mangler {
178+ pub struct Mangler < ' t > {
160179 options : MangleOptions ,
180+ /// An allocator meant to be used for temporary allocations during mangling.
181+ /// It can be cleared after mangling is done, to free up memory for subsequent
182+ /// files or other operations.
183+ temp_allocator : TempAllocator < ' t > ,
161184}
162185
163- impl Mangler {
186+ impl Default for Mangler < ' _ > {
187+ fn default ( ) -> Self {
188+ Self {
189+ options : MangleOptions :: default ( ) ,
190+ temp_allocator : TempAllocator :: Owned ( Allocator :: default ( ) ) ,
191+ }
192+ }
193+ }
194+
195+ impl < ' t > Mangler < ' t > {
164196 #[ must_use]
165197 pub fn new ( ) -> Self {
166198 Self :: default ( )
167199 }
168200
201+ /// Creates a new `Mangler` using an existing temporary allocator. This is an allocator
202+ /// that can be reset after mangling and is only used for temporary allocations during
203+ /// the mangling process. This makes processing multiple files at once much more efficient,
204+ /// because the same memory can be used for mangling each file.
205+ ///
206+ /// # Examples
207+ ///
208+ /// ```rust
209+ /// use oxc_allocator::Allocator;
210+ /// use oxc_mangler::Mangler;
211+ /// use oxc_parser::Parser;
212+ /// use oxc_span::SourceType;
213+ ///
214+ /// let allocator = Allocator::default();
215+ /// let temp_allocator = Allocator::default();
216+ /// let source = "function myFunction(param) { return param + 1; }";
217+ ///
218+ /// let parsed = Parser::new(&allocator, source, SourceType::mjs()).parse();
219+ /// let mangled_symbols = Mangler::new_with_temp_allocator(&temp_allocator)
220+ /// .build(&parsed.program);
221+ ///
222+ /// // Reset the allocator to free temporary memory
223+ /// temp_allocator.reset();
224+ /// ```
225+ ///
226+ /// Processing multiple files:
227+ ///
228+ /// ```rust
229+ /// # use oxc_allocator::Allocator;
230+ /// # use oxc_mangler::Mangler;
231+ /// # use oxc_parser::Parser;
232+ /// # use oxc_span::SourceType;
233+ /// let allocator = Allocator::default();
234+ /// let temp_allocator = Allocator::default();
235+ /// let files = ["function foo() {}", "function bar() {}"];
236+ ///
237+ /// for source in files {
238+ /// let parsed = Parser::new(&allocator, source, SourceType::mjs()).parse();
239+ /// let mangled_symbols = Mangler::new_with_temp_allocator(&temp_allocator)
240+ /// .build(&parsed.program);
241+ /// temp_allocator.reset(); // Free memory between files
242+ /// }
243+ /// ```
244+ #[ must_use]
245+ pub fn new_with_temp_allocator ( temp_allocator : & ' t Allocator ) -> Self {
246+ Self {
247+ options : MangleOptions :: default ( ) ,
248+ temp_allocator : TempAllocator :: Borrowed ( temp_allocator) ,
249+ }
250+ }
251+
169252 #[ must_use]
170253 pub fn with_options ( mut self , options : MangleOptions ) -> Self {
171254 self . options = options;
@@ -216,10 +299,11 @@ impl Mangler {
216299 let ( keep_name_names, keep_name_symbols) =
217300 Mangler :: collect_keep_name_symbols ( self . options . keep_names , scoping, ast_nodes) ;
218301
219- let allocator = Allocator :: default ( ) ;
220-
221302 // All symbols with their assigned slots. Keyed by symbol id.
222- let mut slots = Vec :: from_iter_in ( iter:: repeat_n ( 0 , scoping. symbols_len ( ) ) , & allocator) ;
303+ let mut slots = Vec :: from_iter_in (
304+ iter:: repeat_n ( 0 , scoping. symbols_len ( ) ) ,
305+ self . temp_allocator . as_ref ( ) ,
306+ ) ;
223307
224308 // Stores the lived scope ids for each slot. Keyed by slot number.
225309 let mut slot_liveness: std:: vec:: Vec < FixedBitSet > = vec ! [ ] ;
@@ -300,13 +384,13 @@ impl Mangler {
300384 & keep_name_symbols,
301385 total_number_of_slots,
302386 & slots,
303- & allocator,
304387 ) ;
305388
306389 let root_unresolved_references = scoping. root_unresolved_references ( ) ;
307390 let root_bindings = scoping. get_bindings ( scoping. root_scope_id ( ) ) ;
308391
309- let mut reserved_names = Vec :: with_capacity_in ( total_number_of_slots, & allocator) ;
392+ let mut reserved_names =
393+ Vec :: with_capacity_in ( total_number_of_slots, self . temp_allocator . as_ref ( ) ) ;
310394
311395 let mut count = 0 ;
312396 for _ in 0 ..total_number_of_slots {
@@ -387,12 +471,12 @@ impl Mangler {
387471 keep_name_symbols : & FxHashSet < SymbolId > ,
388472 total_number_of_slots : usize ,
389473 slots : & [ Slot ] ,
390- allocator : & ' a Allocator ,
391474 ) -> Vec < ' a , SlotFrequency < ' a > > {
392475 let root_scope_id = scoping. root_scope_id ( ) ;
393476 let mut frequencies = Vec :: from_iter_in (
394- repeat_with ( || SlotFrequency :: new ( allocator) ) . take ( total_number_of_slots) ,
395- allocator,
477+ repeat_with ( || SlotFrequency :: new ( self . temp_allocator . as_ref ( ) ) )
478+ . take ( total_number_of_slots) ,
479+ self . temp_allocator . as_ref ( ) ,
396480 ) ;
397481
398482 for ( symbol_id, slot) in slots. iter ( ) . copied ( ) . enumerate ( ) {
@@ -463,9 +547,9 @@ struct SlotFrequency<'a> {
463547 pub symbol_ids : Vec < ' a , SymbolId > ,
464548}
465549
466- impl < ' a > SlotFrequency < ' a > {
467- fn new ( allocator : & ' a Allocator ) -> Self {
468- Self { slot : 0 , frequency : 0 , symbol_ids : Vec :: new_in ( allocator ) }
550+ impl < ' t > SlotFrequency < ' t > {
551+ fn new ( temp_allocator : & ' t Allocator ) -> Self {
552+ Self { slot : 0 , frequency : 0 , symbol_ids : Vec :: new_in ( temp_allocator ) }
469553 }
470554}
471555
0 commit comments