@@ -46,6 +46,7 @@ use std::intrinsics;
46
46
use std:: marker:: { PhantomData , Send } ;
47
47
use std:: mem;
48
48
use std:: ptr;
49
+ use std:: slice;
49
50
50
51
use alloc:: heap;
51
52
use alloc:: raw_vec:: RawVec ;
@@ -122,9 +123,8 @@ impl Chunk {
122
123
/// plain-old-data (`Copy` types) and means we don't need to waste time running
123
124
/// their destructors.
124
125
pub struct Arena < ' longer_than_self > {
125
- // The head is separated out from the list as a unbenchmarked
126
- // microoptimization, to avoid needing to case on the list to access the
127
- // head.
126
+ // The heads are separated out from the list as a unbenchmarked
127
+ // microoptimization, to avoid needing to case on the list to access a head.
128
128
head : RefCell < Chunk > ,
129
129
copy_head : RefCell < Chunk > ,
130
130
chunks : RefCell < Vec < Chunk > > ,
@@ -329,6 +329,37 @@ impl<'longer_than_self> Arena<'longer_than_self> {
329
329
}
330
330
}
331
331
}
332
+
333
+ /// Allocates a slice of bytes of requested length. The bytes are not guaranteed to be zero
334
+ /// if the arena has previously been cleared.
335
+ ///
336
+ /// # Panics
337
+ ///
338
+ /// Panics if the requested length is too large and causes overflow.
339
+ pub fn alloc_bytes ( & self , len : usize ) -> & mut [ u8 ] {
340
+ unsafe {
341
+ // Check for overflow.
342
+ self . copy_head . borrow ( ) . fill . get ( ) . checked_add ( len) . expect ( "length overflow" ) ;
343
+ let ptr = self . alloc_copy_inner ( len, 1 ) ;
344
+ intrinsics:: assume ( !ptr. is_null ( ) ) ;
345
+ slice:: from_raw_parts_mut ( ptr as * mut _ , len)
346
+ }
347
+ }
348
+
349
+ /// Clears the arena. Deallocates all but the longest chunk which may be reused.
350
+ pub fn clear ( & mut self ) {
351
+ unsafe {
352
+ self . head . borrow ( ) . destroy ( ) ;
353
+ self . head . borrow ( ) . fill . set ( 0 ) ;
354
+ self . copy_head . borrow ( ) . fill . set ( 0 ) ;
355
+ for chunk in self . chunks . borrow ( ) . iter ( ) {
356
+ if !chunk. is_copy . get ( ) {
357
+ chunk. destroy ( ) ;
358
+ }
359
+ }
360
+ self . chunks . borrow_mut ( ) . clear ( ) ;
361
+ }
362
+ }
332
363
}
333
364
334
365
#[ test]
@@ -495,6 +526,45 @@ impl<T> TypedArena<T> {
495
526
}
496
527
}
497
528
}
529
+ /// Clears the arena. Deallocates all but the longest chunk which may be reused.
530
+ pub fn clear ( & mut self ) {
531
+ unsafe {
532
+ // Clear the last chunk, which is partially filled.
533
+ let mut chunks_borrow = self . chunks . borrow_mut ( ) ;
534
+ let last_idx = chunks_borrow. len ( ) - 1 ;
535
+ self . clear_last_chunk ( & mut chunks_borrow[ last_idx] ) ;
536
+ // If `T` is ZST, code below has no effect.
537
+ for mut chunk in chunks_borrow. drain ( ..last_idx) {
538
+ let cap = chunk. storage . cap ( ) ;
539
+ chunk. destroy ( cap) ;
540
+ }
541
+ }
542
+ }
543
+
544
+ // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
545
+ // chunks.
546
+ fn clear_last_chunk ( & self , last_chunk : & mut TypedArenaChunk < T > ) {
547
+ // Determine how much was filled.
548
+ let start = last_chunk. start ( ) as usize ;
549
+ // We obtain the value of the pointer to the first uninitialized element.
550
+ let end = self . ptr . get ( ) as usize ;
551
+ // We then calculate the number of elements to be dropped in the last chunk,
552
+ // which is the filled area's length.
553
+ let diff = if mem:: size_of :: < T > ( ) == 0 {
554
+ // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
555
+ // the number of zero-sized values in the last and only chunk, just out of caution.
556
+ // Recall that `end` was incremented for each allocated value.
557
+ end - start
558
+ } else {
559
+ ( end - start) / mem:: size_of :: < T > ( )
560
+ } ;
561
+ // Pass that to the `destroy` method.
562
+ unsafe {
563
+ last_chunk. destroy ( diff) ;
564
+ }
565
+ // Reset the chunk.
566
+ self . ptr . set ( last_chunk. start ( ) ) ;
567
+ }
498
568
}
499
569
500
570
impl < T > Drop for TypedArena < T > {
@@ -504,24 +574,14 @@ impl<T> Drop for TypedArena<T> {
504
574
// Determine how much was filled.
505
575
let mut chunks_borrow = self . chunks . borrow_mut ( ) ;
506
576
let mut last_chunk = chunks_borrow. pop ( ) . unwrap ( ) ;
507
- let start = last_chunk. start ( ) as usize ;
508
- let end = self . ptr . get ( ) as usize ;
509
- let diff = if mem:: size_of :: < T > ( ) == 0 {
510
- // Avoid division by zero.
511
- end - start
512
- } else {
513
- ( end - start) / mem:: size_of :: < T > ( )
514
- } ;
515
-
516
- // Pass that to the `destroy` method.
517
- last_chunk. destroy ( diff) ;
518
- // Destroy this chunk.
519
- let _: RawVec < T > = mem:: transmute ( last_chunk) ;
520
-
577
+ // Drop the contents of the last chunk.
578
+ self . clear_last_chunk ( & mut last_chunk) ;
579
+ // The last chunk will be dropped. Destroy all other chunks.
521
580
for chunk in chunks_borrow. iter_mut ( ) {
522
581
let cap = chunk. storage . cap ( ) ;
523
582
chunk. destroy ( cap) ;
524
583
}
584
+ // RawVec handles deallocation of `last_chunk` and `self.chunks`.
525
585
}
526
586
}
527
587
}
@@ -533,6 +593,7 @@ mod tests {
533
593
extern crate test;
534
594
use self :: test:: Bencher ;
535
595
use super :: { Arena , TypedArena } ;
596
+ use std:: rc:: Rc ;
536
597
537
598
#[ allow( dead_code) ]
538
599
struct Point {
@@ -667,10 +728,74 @@ mod tests {
667
728
}
668
729
669
730
#[ test]
670
- pub fn test_zero_sized ( ) {
731
+ pub fn test_typed_arena_zero_sized ( ) {
671
732
let arena = TypedArena :: new ( ) ;
672
733
for _ in 0 ..100000 {
673
734
arena. alloc ( ( ) ) ;
674
735
}
675
736
}
737
+
738
+ #[ test]
739
+ pub fn test_arena_zero_sized ( ) {
740
+ let arena = Arena :: new ( ) ;
741
+ for _ in 0 ..1000 {
742
+ for _ in 0 ..100 {
743
+ arena. alloc ( || ( ) ) ;
744
+ }
745
+ arena. alloc ( || Point {
746
+ x : 1 ,
747
+ y : 2 ,
748
+ z : 3 ,
749
+ } ) ;
750
+ }
751
+ }
752
+
753
+ #[ test]
754
+ pub fn test_typed_arena_clear ( ) {
755
+ let mut arena = TypedArena :: new ( ) ;
756
+ for _ in 0 ..10 {
757
+ arena. clear ( ) ;
758
+ for _ in 0 ..10000 {
759
+ arena. alloc ( Point {
760
+ x : 1 ,
761
+ y : 2 ,
762
+ z : 3 ,
763
+ } ) ;
764
+ }
765
+ }
766
+ }
767
+
768
+ #[ test]
769
+ pub fn test_arena_clear ( ) {
770
+ let mut arena = Arena :: new ( ) ;
771
+ for _ in 0 ..10 {
772
+ arena. clear ( ) ;
773
+ for _ in 0 ..10000 {
774
+ arena. alloc ( || Point {
775
+ x : 1 ,
776
+ y : 2 ,
777
+ z : 3 ,
778
+ } ) ;
779
+ arena. alloc ( || Noncopy {
780
+ string : "hello world" . to_string ( ) ,
781
+ array : vec ! [ ] ,
782
+ } ) ;
783
+ }
784
+ }
785
+ }
786
+
787
+ #[ test]
788
+ pub fn test_arena_alloc_bytes ( ) {
789
+ let arena = Arena :: new ( ) ;
790
+ for i in 0 ..10000 {
791
+ arena. alloc ( || Point {
792
+ x : 1 ,
793
+ y : 2 ,
794
+ z : 3 ,
795
+ } ) ;
796
+ for byte in arena. alloc_bytes ( i % 42 ) . iter_mut ( ) {
797
+ * byte = i as u8 ;
798
+ }
799
+ }
800
+ }
676
801
}
0 commit comments