@@ -42,6 +42,7 @@ use std::cell::{Cell, RefCell};
42
42
use std:: cmp;
43
43
use std:: intrinsics:: { TyDesc , get_tydesc} ;
44
44
use std:: intrinsics;
45
+ use std:: marker;
45
46
use std:: mem;
46
47
use std:: num:: { Int , UnsignedInt } ;
47
48
use std:: ptr;
@@ -88,27 +89,29 @@ impl Chunk {
88
89
/// than objects without destructors. This reduces overhead when initializing
89
90
/// plain-old-data (`Copy` types) and means we don't need to waste time running
90
91
/// their destructors.
91
- pub struct Arena {
92
+ pub struct Arena < ' longer_than_self > {
92
93
// The head is separated out from the list as a unbenchmarked
93
94
// microoptimization, to avoid needing to case on the list to access the
94
95
// head.
95
96
head : RefCell < Chunk > ,
96
97
copy_head : RefCell < Chunk > ,
97
98
chunks : RefCell < Vec < Chunk > > ,
99
+ _invariant : marker:: InvariantLifetime < ' longer_than_self > ,
98
100
}
99
101
100
- impl Arena {
102
+ impl < ' a > Arena < ' a > {
101
103
/// Allocates a new Arena with 32 bytes preallocated.
102
- pub fn new ( ) -> Arena {
104
+ pub fn new ( ) -> Arena < ' a > {
103
105
Arena :: new_with_size ( 32 )
104
106
}
105
107
106
108
/// Allocates a new Arena with `initial_size` bytes preallocated.
107
- pub fn new_with_size ( initial_size : usize ) -> Arena {
109
+ pub fn new_with_size ( initial_size : usize ) -> Arena < ' a > {
108
110
Arena {
109
111
head : RefCell :: new ( chunk ( initial_size, false ) ) ,
110
112
copy_head : RefCell :: new ( chunk ( initial_size, true ) ) ,
111
113
chunks : RefCell :: new ( Vec :: new ( ) ) ,
114
+ _invariant : marker:: InvariantLifetime ,
112
115
}
113
116
}
114
117
}
@@ -122,7 +125,7 @@ fn chunk(size: usize, is_copy: bool) -> Chunk {
122
125
}
123
126
124
127
#[ unsafe_destructor]
125
- impl Drop for Arena {
128
+ impl < ' longer_than_self > Drop for Arena < ' longer_than_self > {
126
129
fn drop ( & mut self ) {
127
130
unsafe {
128
131
destroy_chunk ( & * self . head . borrow ( ) ) ;
@@ -180,7 +183,7 @@ fn un_bitpack_tydesc_ptr(p: usize) -> (*const TyDesc, bool) {
180
183
( ( p & !1 ) as * const TyDesc , p & 1 == 1 )
181
184
}
182
185
183
- impl Arena {
186
+ impl < ' longer_than_self > Arena < ' longer_than_self > {
184
187
fn chunk_size ( & self ) -> usize {
185
188
self . copy_head . borrow ( ) . capacity ( )
186
189
}
@@ -293,7 +296,7 @@ impl Arena {
293
296
/// Allocates a new item in the arena, using `op` to initialize the value,
294
297
/// and returns a reference to it.
295
298
#[ inline]
296
- pub fn alloc < T , F > ( & self , op : F ) -> & mut T where F : FnOnce ( ) -> T {
299
+ pub fn alloc < T : ' longer_than_self , F > ( & self , op : F ) -> & mut T where F : FnOnce ( ) -> T {
297
300
unsafe {
298
301
if intrinsics:: needs_drop :: < T > ( ) {
299
302
self . alloc_noncopy ( op)
@@ -317,20 +320,6 @@ fn test_arena_destructors() {
317
320
}
318
321
}
319
322
320
- #[ test]
321
- fn test_arena_alloc_nested ( ) {
322
- struct Inner { value : usize }
323
- struct Outer < ' a > { inner : & ' a Inner }
324
-
325
- let arena = Arena :: new ( ) ;
326
-
327
- let result = arena. alloc ( || Outer {
328
- inner : arena. alloc ( || Inner { value : 10 } )
329
- } ) ;
330
-
331
- assert_eq ! ( result. inner. value, 10 ) ;
332
- }
333
-
334
323
#[ test]
335
324
#[ should_fail]
336
325
fn test_arena_destructors_fail ( ) {
@@ -365,6 +354,10 @@ pub struct TypedArena<T> {
365
354
366
355
/// A pointer to the first arena segment.
367
356
first : RefCell < * mut TypedArenaChunk < T > > ,
357
+
358
+ /// Marker indicating that dropping the arena causes its owned
359
+ /// instances of `T` to be dropped.
360
+ _own : marker:: PhantomData < T > ,
368
361
}
369
362
370
363
struct TypedArenaChunk < T > {
@@ -460,6 +453,7 @@ impl<T> TypedArena<T> {
460
453
ptr : Cell :: new ( ( * chunk) . start ( ) as * const T ) ,
461
454
end : Cell :: new ( ( * chunk) . end ( ) as * const T ) ,
462
455
first : RefCell :: new ( chunk) ,
456
+ _own : marker:: PhantomData ,
463
457
}
464
458
}
465
459
}
@@ -523,6 +517,41 @@ mod tests {
523
517
z : i32 ,
524
518
}
525
519
520
+ #[ test]
521
+ fn test_arena_alloc_nested ( ) {
522
+ struct Inner { value : u8 }
523
+ struct Outer < ' a > { inner : & ' a Inner }
524
+ enum EI < ' e > { I ( Inner ) , O ( Outer < ' e > ) }
525
+
526
+ struct Wrap < ' a > ( TypedArena < EI < ' a > > ) ;
527
+
528
+ impl < ' a > Wrap < ' a > {
529
+ fn alloc_inner < F : Fn ( ) -> Inner > ( & self , f : F ) -> & Inner {
530
+ let r: & EI = self . 0 . alloc ( EI :: I ( f ( ) ) ) ;
531
+ if let & EI :: I ( ref i) = r {
532
+ i
533
+ } else {
534
+ panic ! ( "mismatch" ) ;
535
+ }
536
+ }
537
+ fn alloc_outer < F : Fn ( ) -> Outer < ' a > > ( & self , f : F ) -> & Outer {
538
+ let r: & EI = self . 0 . alloc ( EI :: O ( f ( ) ) ) ;
539
+ if let & EI :: O ( ref o) = r {
540
+ o
541
+ } else {
542
+ panic ! ( "mismatch" ) ;
543
+ }
544
+ }
545
+ }
546
+
547
+ let arena = Wrap ( TypedArena :: new ( ) ) ;
548
+
549
+ let result = arena. alloc_outer ( || Outer {
550
+ inner : arena. alloc_inner ( || Inner { value : 10 } ) } ) ;
551
+
552
+ assert_eq ! ( result. inner. value, 10 ) ;
553
+ }
554
+
526
555
#[ test]
527
556
pub fn test_copy ( ) {
528
557
let arena = TypedArena :: new ( ) ;
0 commit comments