@@ -45,24 +45,24 @@ pub struct TypedArena<T> {
45
45
end : Cell < * mut T > ,
46
46
47
47
/// A vector of arena chunks.
48
- chunks : RefCell < Vec < TypedArenaChunk < T > > > ,
48
+ chunks : RefCell < Vec < ArenaChunk < T > > > ,
49
49
50
50
/// Marker indicating that dropping the arena causes its owned
51
51
/// instances of `T` to be dropped.
52
52
_own : PhantomData < T > ,
53
53
}
54
54
55
- struct TypedArenaChunk < T > {
55
+ struct ArenaChunk < T = u8 > {
56
56
/// The raw storage for the arena chunk.
57
57
storage : Box < [ MaybeUninit < T > ] > ,
58
58
/// The number of valid entries in the chunk.
59
59
entries : usize ,
60
60
}
61
61
62
- impl < T > TypedArenaChunk < T > {
62
+ impl < T > ArenaChunk < T > {
63
63
#[ 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 }
66
66
}
67
67
68
68
/// Destroys this arena chunk.
@@ -125,6 +125,11 @@ impl<I, T> IterExt<T> for I
125
125
where
126
126
I : IntoIterator < Item = T > ,
127
127
{
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.
128
133
#[ inline]
129
134
default fn alloc_from_iter ( self , arena : & TypedArena < T > ) -> & mut [ T ] {
130
135
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> {
139
144
if len == 0 {
140
145
return & mut [ ] ;
141
146
}
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.
143
148
unsafe {
144
149
let start_ptr = arena. alloc_raw_slice ( len) ;
145
150
self . as_slice ( ) . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -156,7 +161,7 @@ impl<T> IterExt<T> for Vec<T> {
156
161
if len == 0 {
157
162
return & mut [ ] ;
158
163
}
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.
160
165
unsafe {
161
166
let start_ptr = arena. alloc_raw_slice ( len) ;
162
167
self . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -173,7 +178,7 @@ impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
173
178
if len == 0 {
174
179
return & mut [ ] ;
175
180
}
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.
177
182
unsafe {
178
183
let start_ptr = arena. alloc_raw_slice ( len) ;
179
184
self . as_ptr ( ) . copy_to_nonoverlapping ( start_ptr, len) ;
@@ -272,7 +277,7 @@ impl<T> TypedArena<T> {
272
277
// Also ensure that this chunk can fit `additional`.
273
278
new_cap = cmp:: max ( additional, new_cap) ;
274
279
275
- let mut chunk = TypedArenaChunk :: < T > :: new ( new_cap) ;
280
+ let mut chunk = ArenaChunk :: < T > :: new ( new_cap) ;
276
281
self . ptr . set ( chunk. start ( ) ) ;
277
282
self . end . set ( chunk. end ( ) ) ;
278
283
chunks. push ( chunk) ;
@@ -281,7 +286,7 @@ impl<T> TypedArena<T> {
281
286
282
287
// Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
283
288
// chunks.
284
- fn clear_last_chunk ( & self , last_chunk : & mut TypedArenaChunk < T > ) {
289
+ fn clear_last_chunk ( & self , last_chunk : & mut ArenaChunk < T > ) {
285
290
// Determine how much was filled.
286
291
let start = last_chunk. start ( ) as usize ;
287
292
// We obtain the value of the pointer to the first uninitialized element.
@@ -340,7 +345,7 @@ pub struct DroplessArena {
340
345
end : Cell < * mut u8 > ,
341
346
342
347
/// A vector of arena chunks.
343
- chunks : RefCell < Vec < TypedArenaChunk < u8 > > > ,
348
+ chunks : RefCell < Vec < ArenaChunk > > ,
344
349
}
345
350
346
351
unsafe impl Send for DroplessArena { }
@@ -378,7 +383,7 @@ impl DroplessArena {
378
383
// Also ensure that this chunk can fit `additional`.
379
384
new_cap = cmp:: max ( additional, new_cap) ;
380
385
381
- let mut chunk = TypedArenaChunk :: < u8 > :: new ( new_cap) ;
386
+ let mut chunk = ArenaChunk :: new ( new_cap) ;
382
387
self . start . set ( chunk. start ( ) ) ;
383
388
self . end . set ( chunk. end ( ) ) ;
384
389
chunks. push ( chunk) ;
@@ -520,10 +525,19 @@ impl DroplessArena {
520
525
}
521
526
}
522
527
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
+ ///
527
541
#[ rustc_macro_transparency = "semitransparent" ]
528
542
pub macro declare_arena ( [ $( $a: tt $name: ident: $ty: ty, ) * ] ) {
529
543
#[ derive( Default ) ]
@@ -532,7 +546,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
532
546
$( $name: $crate:: TypedArena <$ty>, ) *
533
547
}
534
548
535
- pub trait ArenaAllocatable < ' tcx , T = Self > : Sized {
549
+ pub trait ArenaAllocatable < ' tcx , C = rustc_arena :: IsNotCopy > : Sized {
536
550
fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self ;
537
551
fn allocate_from_iter < ' a > (
538
552
arena : & ' a Arena < ' tcx > ,
@@ -541,7 +555,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
541
555
}
542
556
543
557
// 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 {
545
559
#[ inline]
546
560
fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self {
547
561
arena. dropless . alloc ( self )
@@ -555,7 +569,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
555
569
}
556
570
}
557
571
$(
558
- impl<' tcx> ArenaAllocatable <' tcx, $ty > for $ty {
572
+ impl<' tcx> ArenaAllocatable <' tcx, rustc_arena :: IsNotCopy > for $ty {
559
573
#[ inline]
560
574
fn allocate_on < ' a > ( self , arena : & ' a Arena < ' tcx > ) -> & ' a mut Self {
561
575
if !:: std:: mem:: needs_drop :: < Self > ( ) {
@@ -581,7 +595,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
581
595
582
596
impl<' tcx> Arena <' tcx> {
583
597
#[ 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 {
585
599
value. allocate_on ( self )
586
600
}
587
601
@@ -594,7 +608,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
594
608
self . dropless . alloc_slice ( value)
595
609
}
596
610
597
- pub fn alloc_from_iter < ' a , T : ArenaAllocatable < ' tcx , U > , U > (
611
+ pub fn alloc_from_iter < ' a , T : ArenaAllocatable < ' tcx , C > , C > (
598
612
& ' a self ,
599
613
iter : impl :: std:: iter:: IntoIterator < Item = T > ,
600
614
) -> & ' a mut [ T ] {
@@ -603,5 +617,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
603
617
}
604
618
}
605
619
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
+
606
625
#[ cfg( test) ]
607
626
mod tests;
0 commit comments