@@ -488,5 +488,187 @@ impl DroplessArena {
488488 }
489489}
490490
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+
491673#[ cfg( test) ]
492674mod tests;
0 commit comments