@@ -45,24 +45,24 @@ pub struct TypedArena<T> {
4545 end : Cell < * mut T > ,
4646
4747 /// A vector of arena chunks.
48- chunks : RefCell < Vec < TypedArenaChunk < T > > > ,
48+ chunks : RefCell < Vec < ArenaChunk < T > > > ,
4949
5050 /// Marker indicating that dropping the arena causes its owned
5151 /// instances of `T` to be dropped.
5252 _own : PhantomData < T > ,
5353}
5454
55- struct TypedArenaChunk < T > {
55+ struct ArenaChunk < T = u8 > {
5656 /// The raw storage for the arena chunk.
5757 storage : Box < [ MaybeUninit < T > ] > ,
5858 /// The number of valid entries in the chunk.
5959 entries : usize ,
6060}
6161
62- impl < T > TypedArenaChunk < T > {
62+ impl < T > ArenaChunk < T > {
6363 #[ inline]
64- unsafe fn new ( capacity : usize ) -> TypedArenaChunk < T > {
65- TypedArenaChunk { storage : Box :: new_uninit_slice ( capacity) , entries : 0 }
64+ unsafe fn new ( capacity : usize ) -> ArenaChunk < T > {
65+ ArenaChunk { storage : Box :: new_uninit_slice ( capacity) , entries : 0 }
6666 }
6767
6868 /// Destroys this arena chunk.
@@ -125,6 +125,11 @@ impl<I, T> IterExt<T> for I
125125where
126126 I : IntoIterator < Item = T > ,
127127{
128+ // This default collects into a `SmallVec` and then allocates by copying
129+ // from it. The specializations below for types like `Vec` are more
130+ // efficient, copying directly without the intermediate collecting step.
131+ // This default could be made more efficient, like
132+ // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother.
128133 #[ inline]
129134 default fn alloc_from_iter ( self , arena : & TypedArena < T > ) -> & mut [ T ] {
130135 let vec: SmallVec < [ _ ; 8 ] > = self . into_iter ( ) . collect ( ) ;
@@ -139,7 +144,7 @@ impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
139144 if len == 0 {
140145 return & mut [ ] ;
141146 }
142- // Move the content to the arena by copying and then forgetting it
147+ // Move the content to the arena by copying and then forgetting it.
143148 unsafe {
144149 let start_ptr = arena. alloc_raw_slice ( len) ;
145150 self . as_slice ( ) . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -156,7 +161,7 @@ impl<T> IterExt<T> for Vec<T> {
156161 if len == 0 {
157162 return & mut [ ] ;
158163 }
159- // Move the content to the arena by copying and then forgetting it
164+ // Move the content to the arena by copying and then forgetting it.
160165 unsafe {
161166 let start_ptr = arena. alloc_raw_slice ( len) ;
162167 self . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -173,7 +178,7 @@ impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
173178 if len == 0 {
174179 return & mut [ ] ;
175180 }
176- // Move the content to the arena by copying and then forgetting it
181+ // Move the content to the arena by copying and then forgetting it.
177182 unsafe {
178183 let start_ptr = arena. alloc_raw_slice ( len) ;
179184 self . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -272,7 +277,7 @@ impl<T> TypedArena<T> {
272277 // Also ensure that this chunk can fit `additional`.
273278 new_cap = cmp:: max ( additional, new_cap) ;
274279
275- let mut chunk = TypedArenaChunk :: < T > :: new ( new_cap) ;
280+ let mut chunk = ArenaChunk :: < T > :: new ( new_cap) ;
276281 self . ptr . set ( chunk. start ( ) ) ;
277282 self . end . set ( chunk. end ( ) ) ;
278283 chunks. push ( chunk) ;
@@ -281,7 +286,7 @@ impl<T> TypedArena<T> {
281286
282287 // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
283288 // chunks.
284- fn clear_last_chunk ( & self , last_chunk : & mut TypedArenaChunk < T > ) {
289+ fn clear_last_chunk ( & self , last_chunk : & mut ArenaChunk < T > ) {
285290 // Determine how much was filled.
286291 let start = last_chunk. start ( ) as usize ;
287292 // We obtain the value of the pointer to the first uninitialized element.
@@ -340,7 +345,7 @@ pub struct DroplessArena {
340345 end : Cell < * mut u8 > ,
341346
342347 /// A vector of arena chunks.
343- chunks : RefCell < Vec < TypedArenaChunk < u8 > > > ,
348+ chunks : RefCell < Vec < ArenaChunk > > ,
344349}
345350
346351unsafe impl Send for DroplessArena { }
@@ -378,7 +383,7 @@ impl DroplessArena {
378383 // Also ensure that this chunk can fit `additional`.
379384 new_cap = cmp:: max ( additional, new_cap) ;
380385
381- let mut chunk = TypedArenaChunk :: < u8 > :: new ( new_cap) ;
386+ let mut chunk = ArenaChunk :: new ( new_cap) ;
382387 self . start . set ( chunk. start ( ) ) ;
383388 self . end . set ( chunk. end ( ) ) ;
384389 chunks. push ( chunk) ;
@@ -520,10 +525,19 @@ impl DroplessArena {
520525 }
521526}
522527
523- // Declare an `Arena` containing one dropless arena and many typed arenas (the
524- // types of the typed arenas are specified by the arguments). The dropless
525- // arena will be used for any types that impl `Copy`, and also for any of the
526- // specified types that satisfy `!mem::needs_drop`.
528+ /// Declare an `Arena` containing one dropless arena and many typed arenas (the
529+ /// types of the typed arenas are specified by the arguments).
530+ ///
531+ /// There are three cases of interest.
532+ /// - Types that are `Copy`: these need not be specified in the arguments. They
533+ /// will use the `DroplessArena`.
534+ /// - Types that are `!Copy` and `!Drop`: these must be specified in the
535+ /// arguments. An empty `TypedArena` will be created for each one, but the
536+ /// `DroplessArena` will always be used and the `TypedArena` will stay empty.
537+ /// This is odd but harmless, because an empty arena allocates no memory.
538+ /// - Types that are `!Copy` and `Drop`: these must be specified in the
539+ /// arguments. The `TypedArena` will be used for them.
540+ ///
527541#[ rustc_macro_transparency = "semitransparent" ]
528542pub macro declare_arena ( [ $( $a: tt $name: ident: $ty: ty, ) * ] ) {
529543 #[ derive( Default ) ]
@@ -532,7 +546,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
532546 $( $name: $crate:: TypedArena <$ty>, ) *
533547 }
534548
535- pub trait ArenaAllocatable < ' tcx , T = Self > : Sized {
549+ pub trait ArenaAllocatable < ' tcx , C = rustc_arena :: IsNotCopy > : Sized {
536550 fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self ;
537551 fn allocate_from_iter < ' a > (
538552 arena : & ' a Arena < ' tcx > ,
@@ -541,7 +555,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
541555 }
542556
543557 // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
544- impl < ' tcx , T : Copy > ArenaAllocatable < ' tcx , ( ) > for T {
558+ impl < ' tcx , T : Copy > ArenaAllocatable < ' tcx , rustc_arena :: IsCopy > for T {
545559 #[ inline]
546560 fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self {
547561 arena. dropless . alloc ( self )
@@ -555,7 +569,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
555569 }
556570 }
557571 $(
558- impl<' tcx> ArenaAllocatable <' tcx, $ty > for $ty {
572+ impl<' tcx> ArenaAllocatable <' tcx, rustc_arena :: IsNotCopy > for $ty {
559573 #[ inline]
560574 fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self {
561575 if !:: std:: mem:: needs_drop :: < Self > ( ) {
@@ -581,7 +595,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
581595
582596 impl<' tcx> Arena <' tcx> {
583597 #[ inline]
584- pub fn alloc < T : ArenaAllocatable < ' tcx , U > , U > ( & self , value : T ) -> & mut T {
598+ pub fn alloc < T : ArenaAllocatable < ' tcx , C > , C > ( & self , value : T ) -> & mut T {
585599 value. allocate_on ( self )
586600 }
587601
@@ -594,7 +608,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
594608 self . dropless . alloc_slice ( value)
595609 }
596610
597- pub fn alloc_from_iter < ' a , T : ArenaAllocatable < ' tcx , U > , U > (
611+ pub fn alloc_from_iter < ' a , T : ArenaAllocatable < ' tcx , C > , C > (
598612 & ' a self ,
599613 iter : impl :: std:: iter:: IntoIterator < Item = T > ,
600614 ) -> & ' a mut [ T ] {
@@ -603,5 +617,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
603617 }
604618}
605619
620+ // Marker types that let us give different behaviour for arenas allocating
621+ // `Copy` types vs `!Copy` types.
622+ pub struct IsCopy ;
623+ pub struct IsNotCopy ;
624+
606625#[ cfg( test) ]
607626mod tests;
0 commit comments