@@ -488,5 +488,187 @@ impl DroplessArena {
488
488
}
489
489
}
490
490
491
+ /// Calls the destructor for an object when dropped.
492
+ struct DropType {
493
+ drop_fn : unsafe fn ( * mut u8 ) ,
494
+ obj : * mut u8 ,
495
+ }
496
+
497
+ unsafe fn drop_for_type < T > ( to_drop : * mut u8 ) {
498
+ std:: ptr:: drop_in_place ( to_drop as * mut T )
499
+ }
500
+
501
+ impl Drop for DropType {
502
+ fn drop ( & mut self ) {
503
+ unsafe { ( self . drop_fn ) ( self . obj ) }
504
+ }
505
+ }
506
+
507
+ /// An arena which can be used to allocate any type.
508
+ /// Allocating in this arena is unsafe since the type system
509
+ /// doesn't know which types it contains. In order to
510
+ /// allocate safely, you must store a PhantomData<T>
511
+ /// alongside this arena for each type T you allocate.
512
+ #[ derive( Default ) ]
513
+ pub struct DropArena {
514
+ /// A list of destructors to run when the arena drops.
515
+ /// Ordered so `destructors` gets dropped before the arena
516
+ /// since its destructor can reference memory in the arena.
517
+ destructors : RefCell < Vec < DropType > > ,
518
+ arena : DroplessArena ,
519
+ }
520
+
521
+ impl DropArena {
522
+ #[ inline]
523
+ pub unsafe fn alloc < T > ( & self , object : T ) -> & mut T {
524
+ let mem =
525
+ self . arena . alloc_raw ( mem:: size_of :: < T > ( ) , mem:: align_of :: < T > ( ) ) as * mut _ as * mut T ;
526
+ // Write into uninitialized memory.
527
+ ptr:: write ( mem, object) ;
528
+ let result = & mut * mem;
529
+ // Record the destructor after doing the allocation as that may panic
530
+ // and would cause `object`'s destuctor to run twice if it was recorded before
531
+ self . destructors
532
+ . borrow_mut ( )
533
+ . push ( DropType { drop_fn : drop_for_type :: < T > , obj : result as * mut T as * mut u8 } ) ;
534
+ result
535
+ }
536
+
537
+ #[ inline]
538
+ pub unsafe fn alloc_from_iter < T , I : IntoIterator < Item = T > > ( & self , iter : I ) -> & mut [ T ] {
539
+ let mut vec: SmallVec < [ _ ; 8 ] > = iter. into_iter ( ) . collect ( ) ;
540
+ if vec. is_empty ( ) {
541
+ return & mut [ ] ;
542
+ }
543
+ let len = vec. len ( ) ;
544
+
545
+ let start_ptr = self
546
+ . arena
547
+ . alloc_raw ( len. checked_mul ( mem:: size_of :: < T > ( ) ) . unwrap ( ) , mem:: align_of :: < T > ( ) )
548
+ as * mut _ as * mut T ;
549
+
550
+ let mut destructors = self . destructors . borrow_mut ( ) ;
551
+ // Reserve space for the destructors so we can't panic while adding them
552
+ destructors. reserve ( len) ;
553
+
554
+ // Move the content to the arena by copying it and then forgetting
555
+ // the content of the SmallVec
556
+ vec. as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
557
+ mem:: forget ( vec. drain ( ..) ) ;
558
+
559
+ // Record the destructors after doing the allocation as that may panic
560
+ // and would cause `object`'s destuctor to run twice if it was recorded before
561
+ for i in 0 ..len {
562
+ destructors. push ( DropType {
563
+ drop_fn : drop_for_type :: < T > ,
564
+ obj : start_ptr. offset ( i as isize ) as * mut u8 ,
565
+ } ) ;
566
+ }
567
+
568
+ slice:: from_raw_parts_mut ( start_ptr, len)
569
+ }
570
+ }
571
+
572
+ #[ macro_export]
573
+ macro_rules! arena_for_type {
574
+ ( [ ] [ $ty: ty] ) => {
575
+ $crate:: TypedArena <$ty>
576
+ } ;
577
+ ( [ few $( , $attrs: ident) * ] [ $ty: ty] ) => {
578
+ :: std:: marker:: PhantomData <$ty>
579
+ } ;
580
+ ( [ $ignore: ident $( , $attrs: ident) * ] $args: tt) => {
581
+ $crate:: arena_for_type!( [ $( $attrs) ,* ] $args)
582
+ } ;
583
+ }
584
+
585
+ #[ macro_export]
586
+ macro_rules! which_arena_for_type {
587
+ ( [ ] [ $arena: expr] ) => {
588
+ :: std:: option:: Option :: Some ( $arena)
589
+ } ;
590
+ ( [ few$( , $attrs: ident) * ] [ $arena: expr] ) => {
591
+ :: std:: option:: Option :: None
592
+ } ;
593
+ ( [ $ignore: ident$( , $attrs: ident) * ] $args: tt) => {
594
+ $crate:: which_arena_for_type!( [ $( $attrs) ,* ] $args)
595
+ } ;
596
+ }
597
+
598
+ #[ macro_export]
599
+ macro_rules! declare_arena {
600
+ ( [ ] , [ $( $a: tt $name: ident: $ty: ty, ) * ] , $tcx: lifetime) => {
601
+ #[ derive( Default ) ]
602
+ pub struct Arena <$tcx> {
603
+ pub dropless: $crate:: DroplessArena ,
604
+ drop: $crate:: DropArena ,
605
+ $( $name: $crate:: arena_for_type!( $a[ $ty] ) , ) *
606
+ }
607
+
608
+ #[ marker]
609
+ pub trait ArenaAllocatable { }
610
+
611
+ impl <T : Copy > ArenaAllocatable for T { }
612
+
613
+ unsafe trait ArenaField <' tcx>: Sized {
614
+ /// Returns a specific arena to allocate from.
615
+ /// If `None` is returned, the `DropArena` will be used.
616
+ fn arena<' a>( arena: & ' a Arena <' tcx>) -> Option <& ' a $crate:: TypedArena <Self >>;
617
+ }
618
+
619
+ unsafe impl <' tcx, T > ArenaField <' tcx> for T {
620
+ #[ inline]
621
+ default fn arena<' a>( _: & ' a Arena <' tcx>) -> Option <& ' a $crate:: TypedArena <Self >> {
622
+ panic!( )
623
+ }
624
+ }
625
+
626
+ $(
627
+ #[ allow( unused_lifetimes) ]
628
+ impl <$tcx> ArenaAllocatable for $ty { }
629
+ unsafe impl <$tcx> ArenaField <$tcx> for $ty {
630
+ #[ inline]
631
+ fn arena<' a>( _arena: & ' a Arena <$tcx>) -> Option <& ' a $crate:: TypedArena <Self >> {
632
+ $crate:: which_arena_for_type!( $a[ & _arena. $name] )
633
+ }
634
+ }
635
+ ) *
636
+
637
+ impl <' tcx> Arena <' tcx> {
638
+ #[ inline]
639
+ pub fn alloc<T : ArenaAllocatable >( & self , value: T ) -> & mut T {
640
+ if !:: std:: mem:: needs_drop:: <T >( ) {
641
+ return self . dropless. alloc( value) ;
642
+ }
643
+ match <T as ArenaField <' tcx>>:: arena( self ) {
644
+ :: std:: option:: Option :: Some ( arena) => arena. alloc( value) ,
645
+ :: std:: option:: Option :: None => unsafe { self . drop. alloc( value) } ,
646
+ }
647
+ }
648
+
649
+ #[ inline]
650
+ pub fn alloc_slice<T : :: std:: marker:: Copy >( & self , value: & [ T ] ) -> & mut [ T ] {
651
+ if value. is_empty( ) {
652
+ return & mut [ ] ;
653
+ }
654
+ self . dropless. alloc_slice( value)
655
+ }
656
+
657
+ pub fn alloc_from_iter<' a, T : ArenaAllocatable >(
658
+ & ' a self ,
659
+ iter: impl :: std:: iter:: IntoIterator <Item = T >,
660
+ ) -> & ' a mut [ T ] {
661
+ if !:: std:: mem:: needs_drop:: <T >( ) {
662
+ return self . dropless. alloc_from_iter( iter) ;
663
+ }
664
+ match <T as ArenaField <' tcx>>:: arena( self ) {
665
+ :: std:: option:: Option :: Some ( arena) => arena. alloc_from_iter( iter) ,
666
+ :: std:: option:: Option :: None => unsafe { self . drop. alloc_from_iter( iter) } ,
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+
491
673
#[ cfg( test) ]
492
674
mod tests;
0 commit comments