diff options
| author | Mark-Simulacrum <mark.simulacrum@gmail.com> | 2016-10-17 15:03:40 -0600 |
|---|---|---|
| committer | Mark-Simulacrum <mark.simulacrum@gmail.com> | 2016-10-19 06:55:34 -0600 |
| commit | a714c2a15c8cc36dc2cce36e32dfe3a8fc836532 (patch) | |
| tree | 9b3bb3ce2a860634b1b7ad5f7b3a458a84b461b3 /src | |
| parent | 0c429872a32c3005cf2b347025163361218634a4 (diff) | |
| download | rust-a714c2a15c8cc36dc2cce36e32dfe3a8fc836532.tar.gz rust-a714c2a15c8cc36dc2cce36e32dfe3a8fc836532.zip | |
Add TypedArena::alloc_slice.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libarena/lib.rs | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 4986c9850d7..cfbd29571f7 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -46,6 +46,7 @@ use std::intrinsics; use std::marker::{PhantomData, Send}; use std::mem; use std::ptr; +use std::slice; use alloc::heap; use alloc::raw_vec::RawVec; @@ -133,7 +134,7 @@ impl<T> TypedArena<T> { #[inline] pub fn alloc(&self, object: T) -> &mut T { if self.ptr == self.end { - self.grow() + self.grow(1) } unsafe { @@ -154,24 +155,56 @@ impl<T> TypedArena<T> { } } + /// Allocates a slice of objects that are copy into the `TypedArena`, returning a mutable + /// reference to it. Will panic if passed a zero-sized types. + #[inline] + pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] + where T: Copy { + assert!(mem::size_of::<T>() != 0); + if slice.len() == 0 { + return unsafe { slice::from_raw_parts_mut(heap::EMPTY as *mut T, 0) }; + } + + let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; + let at_least_bytes = slice.len() * mem::size_of::<T>(); + if available_capacity_bytes < at_least_bytes { + self.grow(slice.len()); + } + + unsafe { + let start_ptr = self.ptr.get(); + let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len()); + self.ptr.set(start_ptr.offset(arena_slice.len() as isize)); + arena_slice.copy_from_slice(slice); + arena_slice + } + } + /// Grows the arena. #[inline(never)] #[cold] - fn grow(&self) { + fn grow(&self, n: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); - let (chunk, new_capacity); + let (chunk, mut new_capacity); if let Some(last_chunk) = chunks.last_mut() { - if last_chunk.storage.double_in_place() { + let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; + let currently_used_cap = used_bytes / mem::size_of::<T>(); + if last_chunk.storage.reserve_in_place(currently_used_cap, n) { self.end.set(last_chunk.end()); return; } else { let prev_capacity = last_chunk.storage.cap(); - new_capacity = prev_capacity.checked_mul(2).unwrap(); + loop { + new_capacity = prev_capacity.checked_mul(2).unwrap(); + if new_capacity >= currently_used_cap + n { + break; + } + } } } else { let elem_size = cmp::max(1, mem::size_of::<T>()); - new_capacity = cmp::max(1, PAGE / elem_size); + new_capacity = cmp::max(n, PAGE / elem_size); } chunk = TypedArenaChunk::<T>::new(new_capacity); self.ptr.set(chunk.start()); |
