1+ //! Module containing the `Arena` and `Uninitialized` structs. For convenience the
2+ //! `Arena` is exported at the root of the crate.
3+
14use std:: mem:: size_of;
25use std:: cell:: Cell ;
36
@@ -16,8 +19,57 @@ pub struct Arena {
1619 offset : Cell < usize >
1720}
1821
22+ /// A pointer to an uninitialized region of memory.
23+ pub struct Uninitialized < ' arena , T : ' arena > {
24+ pointer : & ' arena mut T ,
25+ }
26+
27+ impl < ' arena , T : ' arena > Uninitialized < ' arena , T > {
28+ /// Initialize the memory at the pointer with a given value.
29+ #[ inline]
30+ pub fn init ( self , value : T ) -> & ' arena T {
31+ * self . pointer = value;
32+
33+ & * self . pointer
34+ }
35+
36+ /// Get a reference to the pointer without writing to it.
37+ ///
38+ /// **Reading from this reference without calling `init` is undefined behavior.**
39+ #[ inline]
40+ pub unsafe fn as_ref ( & self ) -> & ' arena T {
41+ & * ( self . pointer as * const T )
42+ }
43+
44+ /// Convert the `Uninitialized` to a regular mutable reference.
45+ ///
46+ /// **Reading from this reference without calling `init` is undefined behavior.**
47+ #[ inline]
48+ pub unsafe fn into_mut ( self ) -> & ' arena mut T {
49+ self . pointer
50+ }
51+
52+ /// Convert a raw pointer to an `Uninitialized`. This method is unsafe since it can
53+ /// bind to arbitrary lifetimes.
54+ #[ inline]
55+ pub unsafe fn from_raw ( pointer : * mut T ) -> Self {
56+ Uninitialized {
57+ pointer : & mut * pointer,
58+ }
59+ }
60+ }
61+
62+ impl < ' arena , T : ' arena > From < & ' arena mut T > for Uninitialized < ' arena , T > {
63+ #[ inline]
64+ fn from ( pointer : & ' arena mut T ) -> Self {
65+ Uninitialized {
66+ pointer
67+ }
68+ }
69+ }
70+
1971impl Arena {
20- /// Create a new arena with a single preallocated 64KiB page
72+ /// Create a new arena with a single preallocated 64KiB page.
2173 pub fn new ( ) -> Self {
2274 let mut store = vec ! [ Vec :: with_capacity( ARENA_BLOCK ) ] ;
2375 let ptr = store[ 0 ] . as_mut_ptr ( ) ;
@@ -31,55 +83,53 @@ impl Arena {
3183
3284 /// Put the value onto the page of the arena and return a reference to it.
3385 #[ inline]
34- pub fn alloc < ' a , T : Sized + Copy > ( & ' a self , val : T ) -> & ' a T {
35- unsafe {
36- let ptr = self . alloc_uninitialized ( ) ;
37- * ptr = val;
38- & * ptr
39- }
86+ pub fn alloc < ' arena , T : Sized + Copy > ( & ' arena self , value : T ) -> & ' arena T {
87+ self . alloc_uninitialized ( ) . init ( value)
4088 }
4189
42- /// Allocate enough bytes for the type `T`, then return a pointer to the memory.
43- /// Memory behind the pointer is uninitialized, can contain garbage and reading
44- /// from it is undefined behavior.
90+ /// Allocate enough bytes for the type `T`, then return an `Uninitialized` pointer to the memory.
4591 #[ inline]
46- pub unsafe fn alloc_uninitialized < ' a , T : Sized + Copy > ( & ' a self ) -> & ' a mut T {
47- & mut * ( self . require ( size_of :: < T > ( ) ) as * mut T )
92+ pub fn alloc_uninitialized < ' arena , T : Sized + Copy > ( & ' arena self ) -> Uninitialized < ' arena , T > {
93+ Uninitialized {
94+ pointer : unsafe { & mut * ( self . require ( size_of :: < T > ( ) ) as * mut T ) }
95+ }
4896 }
4997
50- /// Allocate an `&str ` slice onto the arena and return a reference to it. This is
51- /// useful when the original slice has an undefined lifetime.
98+ /// Allocate a slice of `T ` slice onto the arena and return a reference to it.
99+ /// This is useful when the original slice has an undefined lifetime.
52100 ///
53- /// Note: static slices (`&'static str `) can be safely used in place of arena-bound
101+ /// Note: static slices (`&'static [T] `) can be safely used in place of arena-bound
54102 /// slices without having to go through this method.
55- pub fn alloc_str < ' a > ( & ' a self , val : & str ) -> & ' a str {
56- let offset = self . offset . get ( ) ;
57- let alignment = size_of :: < usize > ( ) - ( val. len ( ) % size_of :: < usize > ( ) ) ;
58- let cap = offset + val. len ( ) + alignment;
59-
60- if cap > ARENA_BLOCK {
61- return self . alloc_string ( val. into ( ) ) ;
62- }
63-
64- self . offset . set ( cap) ;
103+ pub fn alloc_slice < ' arena , T : Copy > ( & ' arena self , val : & [ T ] ) -> & ' arena [ T ] {
104+ let ptr = self . require ( val. len ( ) * size_of :: < T > ( ) ) as * mut T ;
65105
66106 unsafe {
67107 use std:: ptr:: copy_nonoverlapping;
68- use std:: str:: from_utf8_unchecked;
69108 use std:: slice:: from_raw_parts;
70109
71- let ptr = self . ptr . get ( ) . offset ( offset as isize ) ;
72110 copy_nonoverlapping ( val. as_ptr ( ) , ptr, val. len ( ) ) ;
111+ from_raw_parts ( ptr, val. len ( ) )
112+ }
113+ }
114+
115+ /// Allocate an `&str` slice onto the arena and return a reference to it. This is
116+ /// useful when the original slice has an undefined lifetime.
117+ ///
118+ /// Note: static slices (`&'static str`) can be safely used in place of arena-bound
119+ /// slices without having to go through this method.
120+ pub fn alloc_str < ' arena > ( & ' arena self , val : & str ) -> & ' arena str {
121+ unsafe {
122+ use std:: str:: from_utf8_unchecked;
73123
74- from_utf8_unchecked ( from_raw_parts ( ptr , val. len ( ) ) )
124+ from_utf8_unchecked ( self . alloc_slice ( val. as_bytes ( ) ) )
75125 }
76126 }
77127
78128 /// Allocate an `&str` slice onto the arena as null terminated C-style string.
79129 /// No checks are performed on the source and whether or not it already contains
80130 /// any nul bytes. While this does not create any memory issues, it assumes that
81131 /// the reader of the source can deal with malformed source.
82- pub fn alloc_str_with_nul < ' a > ( & ' a self , val : & str ) -> * const u8 {
132+ pub fn alloc_str_with_nul < ' arena > ( & ' arena self , val : & str ) -> * const u8 {
83133 let len_with_zero = val. len ( ) + 1 ;
84134 let ptr = self . require ( len_with_zero) ;
85135
@@ -94,7 +144,7 @@ impl Arena {
94144
95145 /// Pushes the `String` as it's own page onto the arena and returns a reference to it.
96146 /// This does not copy or reallocate the original `String`.
97- pub fn alloc_string < ' a > ( & ' a self , val : String ) -> & ' a str {
147+ pub fn alloc_string < ' arena > ( & ' arena self , val : String ) -> & ' arena str {
98148 let len = val. len ( ) ;
99149 let ptr = self . alloc_vec ( val. into_bytes ( ) ) ;
100150
@@ -128,10 +178,9 @@ impl Arena {
128178 return self . alloc_bytes ( size) ;
129179 }
130180
131- // This should also be optimized away.
132181 let size = match size % size_of :: < usize > ( ) {
133182 0 => size,
134- n => size + n
183+ n => size + ( size_of :: < usize > ( ) - n ) ,
135184 } ;
136185
137186 let offset = self . offset . get ( ) ;
@@ -209,7 +258,7 @@ mod test {
209258 assert_eq ! ( arena. alloc( 0u64 ) , & 0 ) ;
210259 assert_eq ! ( arena. alloc( 42u64 ) , & 42 ) ;
211260
212- unsafe { arena. alloc_uninitialized :: < [ usize ; 1024 * 1024 ] > ( ) } ;
261+ arena. alloc_uninitialized :: < [ usize ; 1024 * 1024 ] > ( ) ;
213262
214263 // Still writes to the first page
215264 assert_eq ! ( arena. offset. get( ) , 8 * 2 ) ;
@@ -226,6 +275,25 @@ mod test {
226275 assert_eq ! ( arena. store. get_mut( ) [ 1 ] . capacity( ) , size_of:: <usize >( ) * 1024 * 1024 ) ;
227276 }
228277
278+ #[ test]
279+ fn alloc_slice ( ) {
280+ let arena = Arena :: new ( ) ;
281+
282+ assert_eq ! ( arena. alloc_slice( & [ 10u16 , 20u16 ] ) , & [ 10u16 , 20u16 ] [ ..] ) ;
283+ assert_eq ! ( arena. offset. get( ) , 8 ) ;
284+ }
285+
286+ #[ test]
287+ fn aligns_slice_allocs ( ) {
288+ let arena = Arena :: new ( ) ;
289+
290+ assert_eq ! ( arena. alloc_slice( b"foo" ) , b"foo" ) ;
291+ assert_eq ! ( arena. offset. get( ) , 8 ) ;
292+
293+ assert_eq ! ( arena. alloc_slice( b"doge to the moon!" ) , b"doge to the moon!" ) ;
294+ assert_eq ! ( arena. offset. get( ) , 32 ) ;
295+ }
296+
229297 #[ test]
230298 fn aligns_str_allocs ( ) {
231299 let arena = Arena :: new ( ) ;
0 commit comments