From 6eacd486f969bea65db30c489b07baf63bc11d00 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 6 Dec 2017 17:32:36 +0100 Subject: [PATCH 1/3] Add alloc_many --- src/arena.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/arena.rs b/src/arena.rs index c435b4b..75e2570 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -13,7 +13,7 @@ const ARENA_BLOCK: usize = 64 * 1024; pub struct Arena { store: Cell>>, ptr: Cell<*mut u8>, - offset: Cell + offset: Cell, } impl Arena { @@ -29,6 +29,46 @@ impl Arena { } } + /// Allocate many items at once, without reallocating + #[inline] + pub fn alloc_many<'a, T: Sized + Copy>(&'a self, mut vals: Vec) -> &'a [T] { + use std::{mem, slice, ptr}; + + if vals.is_empty() { + return &[]; + } + + let len = vals.len(); + let bytes = len * mem::size_of::(); + + let store = self.store + .replace(Default::default()); + + let should_copy = store.last() + .map(|last| bytes <= last.capacity() - last.len()) + .unwrap_or(false); + + self.store.replace(store); + + if should_copy { + let ptr = self.require(bytes); + unsafe { ptr::copy_nonoverlapping(vals.as_ptr() as _, ptr, bytes) }; + + unsafe { slice::from_raw_parts(ptr as _, len) } + } else { + let p = vals.as_mut_ptr(); + let cap = vals.capacity(); + + mem::forget(vals); + + let out = self.alloc_vec(unsafe { + Vec::from_raw_parts(p as _, len * mem::size_of::(), cap * mem::size_of::()) + }); + + unsafe { slice::from_raw_parts(out as _, len) } + } + } + /// Put the value onto the page of the arena and return a reference to it. #[inline] pub fn alloc<'a, T: Sized + Copy>(&'a self, val: T) -> &'a T { @@ -202,6 +242,17 @@ mod test { assert_eq!(arena.store.get_mut().len(), 1); } + #[test] + fn allocate_some_vecs() { + let arena = Arena::new(); + + let vecs = vec![vec![1u64, 2, 3, 4], vec![7; ARENA_BLOCK * 2], vec![]]; + + for vec in vecs { + assert_eq!(arena.alloc_many(vec.clone()), &vec[..]); + } + } + #[test] fn allocate_huge_heap() { let arena = Arena::new(); From ccf35ff918d1b257145a4070c5a9ccda180893b1 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 6 Dec 2017 17:32:46 +0100 Subject: [PATCH 2/3] Rustfmt --- src/arena.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index 75e2570..f5c1298 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -25,7 +25,7 @@ impl Arena { Arena { store: Cell::new(store), ptr: Cell::new(ptr), - offset: Cell::new(0) + offset: Cell::new(0), } } @@ -171,7 +171,7 @@ impl Arena { // This should also be optimized away. let size = match size % size_of::() { 0 => size, - n => size + n + n => size + n, }; let offset = self.offset.get(); @@ -274,7 +274,10 @@ mod test { assert_eq!(arena.store.get_mut().len(), 2); // Second page is appropriately large - assert_eq!(arena.store.get_mut()[1].capacity(), size_of::() * 1024 * 1024); + assert_eq!( + arena.store.get_mut()[1].capacity(), + size_of::() * 1024 * 1024 + ); } #[test] @@ -295,6 +298,11 @@ mod test { let allocated = unsafe { ::std::slice::from_raw_parts(ptr, 12) }; assert_eq!(arena.offset.get(), 16); - assert_eq!(allocated, &[b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', 0]); + assert_eq!( + allocated, + &[ + b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', 0 + ] + ); } } From aebe31c99683563c21ac061bc3bba2185d778ee4 Mon Sep 17 00:00:00 2001 From: Vurich Date: Thu, 7 Dec 2017 18:22:25 +0100 Subject: [PATCH 3/3] Make alloc_many take a cow --- src/arena.rs | 53 ++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index f5c1298..4366a6b 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -1,5 +1,6 @@ use std::mem::size_of; use std::cell::Cell; +use std::borrow::Cow; const ARENA_BLOCK: usize = 64 * 1024; @@ -31,41 +32,45 @@ impl Arena { /// Allocate many items at once, without reallocating #[inline] - pub fn alloc_many<'a, T: Sized + Copy>(&'a self, mut vals: Vec) -> &'a [T] { - use std::{mem, slice, ptr}; + pub fn alloc_many<'input, 'output, T: Sized + Copy + 'input, V: Into>>( + &'output self, + vals: V, + ) -> &'output [T] { + use std::{mem, ptr, slice}; - if vals.is_empty() { + let vals = vals.into(); + + if vals.as_ref().is_empty() { return &[]; } - let len = vals.len(); + let len = vals.as_ref().len(); let bytes = len * mem::size_of::(); - let store = self.store - .replace(Default::default()); - - let should_copy = store.last() - .map(|last| bytes <= last.capacity() - last.len()) - .unwrap_or(false); + match vals { + Cow::Owned(mut vec) => { + let p = vec.as_mut_ptr(); + let cap = vec.capacity(); - self.store.replace(store); + mem::forget(vec); - if should_copy { - let ptr = self.require(bytes); - unsafe { ptr::copy_nonoverlapping(vals.as_ptr() as _, ptr, bytes) }; - - unsafe { slice::from_raw_parts(ptr as _, len) } - } else { - let p = vals.as_mut_ptr(); - let cap = vals.capacity(); + let out = self.alloc_vec(unsafe { + Vec::from_raw_parts( + p as _, + len * mem::size_of::(), + cap * mem::size_of::(), + ) + }); - mem::forget(vals); + unsafe { slice::from_raw_parts(out as _, len) } + } + Cow::Borrowed(slice) => { + let ptr = self.require(bytes); - let out = self.alloc_vec(unsafe { - Vec::from_raw_parts(p as _, len * mem::size_of::(), cap * mem::size_of::()) - }); + unsafe { ptr::copy_nonoverlapping(slice.as_ptr() as _, ptr, bytes) }; - unsafe { slice::from_raw_parts(out as _, len) } + unsafe { slice::from_raw_parts(ptr as _, len) } + } } }