@@ -4,65 +4,97 @@ use crate::NonZeroLayout;
44use crate :: LocalAlloc ;
55
66/// An allocation without tracked lifetime.
7+ #[ derive( Copy , Clone ) ]
78pub struct Allocation {
89 ptr : NonNull < u8 > ,
910 layout : NonZeroLayout ,
1011}
1112
1213/// A references to an allocator.
1314///
14- /// Allocations must be live for the lifetime of `self`. That is one must be able to move the
15- /// `self` and keep all allocations. In particular, a reference to a [`LocalAlloc`] is an
16- /// `AllocRef`.
15+ /// Allocations created from this instance are valid for the lifetime of `self`. That is one must
16+ /// be able to move the `self` and all allocations remain valid. In particular, a reference to a
17+ /// [`LocalAlloc`] is an `AllocRef` as it is an immutable pin.
18+ ///
19+ /// An allocation is said to be live when it is valid and has not been passed to `dealloc` and has
20+ /// not been passed to `realloc` that returned `Some(_)`.
21+ ///
22+ /// Note that all methods require being passed some existing allocation, even if they do not
23+ /// consume it. See `InitialAllocRef` for those that do not.
1724///
1825/// [`LocalAlloc`]: trait.LocalAlloc.html
1926pub unsafe trait AllocRef {
2027 /// Allocate one block of memory.
2128 ///
22- /// The callee guarantees that a successful return contains a pointer that is valid for **at
23- /// least** the layout requested by the caller.
24- fn alloc ( & mut self , layout : NonZeroLayout ) -> Option < Allocation > ;
25-
26- /// Deallocate a block previously allocated.
27- /// # Safety
28- /// The caller must ensure that:
29- /// * `alloc` has been previously returned from a call to `alloc`.
30- /// * There are no more pointer to the allocation.
31- unsafe fn dealloc ( & mut self , alloc : Allocation ) ;
29+ /// The `existing` allocation can be used by the `AllocRef` to uniquely identify the allocator
30+ /// that is used internaly. It must be valid for the same `AllocRef`.
31+ ///
32+ /// The callee guarantees that a successful return contains a pointer that fits the layout
33+ /// requested by the caller and the layout in the struct is the same as requested.
34+ unsafe fn alloc_from ( & mut self , existing : Allocation , layout : NonZeroLayout ) -> Option < Allocation > ;
3235
3336 /// Allocate a block of memory initialized with zeros.
3437 ///
35- /// The callee guarantees that a successful return contains a pointer that is valid for **at
36- /// least** the layout requested by the caller and the contiguous region of bytes, starting at
37- /// the pointer and with the size of the returned layout, is initialized and zeroed.
38- fn alloc_zeroed ( & mut self , layout : NonZeroLayout )
38+ /// The callee guarantees that a successful return contains a pointer that fits the layout
39+ /// requested by the caller and the layout in the struct is the same as requested.
40+ unsafe fn alloc_zeroed_from ( & mut self , existing : Allocation , layout : NonZeroLayout )
3941 -> Option < Allocation >
4042 {
41- let allocation = self . alloc ( layout) ?;
42- unsafe {
43- write_bytes ( allocation. ptr . as_ptr ( ) , 0u8 , allocation. layout . size ( ) . into ( ) ) ;
44- }
43+ let allocation = self . alloc_from ( existing, layout) ?;
44+ write_bytes ( allocation. ptr . as_ptr ( ) , 0u8 , allocation. layout . size ( ) . into ( ) ) ;
4545 Some ( allocation)
4646 }
4747
48+ /// Deallocate a block previously allocated.
49+ /// # Safety
50+ /// The caller must ensure that:
51+ /// * `alloc` has been previously returned from a call to `alloc`.
52+ /// * There are no more pointer to the allocation.
53+ unsafe fn dealloc ( & mut self , alloc : Allocation ) ;
54+
4855 /// Change the layout of a block previously allocated.
4956 ///
50- /// The callee guarantees that a successful return contains a pointer that is valid for **at
51- /// least** the layout requested by the caller and the contiguous region of bytes, starting at
52- /// the pointer and with the size of the returned layout, is initialized with the prefix of the
53- /// previous allocation that is still valid.
57+ /// The callee guarantees that a successful return contains a pointer that it fits the layout
58+ /// requested by the caller and the contiguous region of bytes, starting at the pointer and
59+ /// with the size of the returned layout, is initialized with the prefix of the previous
60+ /// allocation that is still valid, and that the layout in the returned struct is the same as
61+ /// requested.
5462 unsafe fn realloc ( & mut self , alloc : Allocation , layout : NonZeroLayout )
5563 -> Option < Allocation >
5664 {
57- let new_alloc = self . alloc ( layout) ?;
65+ let new_alloc = self . alloc_from ( alloc , layout) ?;
5866 copy_nonoverlapping (
5967 alloc. ptr . as_ptr ( ) ,
6068 new_alloc. ptr . as_ptr ( ) ,
6169 layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ) ;
70+ self . dealloc ( alloc) ;
6271 Some ( new_alloc)
6372 }
6473}
6574
75+ /// A trait for an `AllocRef` that requires no existing allocation to allocate.
76+ pub unsafe trait InitialAllocRef : AllocRef {
77+ /// Allocate one block of memory.
78+ ///
79+ /// The callee guarantees that a successful return contains a pointer that fits the layout
80+ /// requested by the caller and the layout in the struct is the same as requested.
81+ fn alloc ( & mut self , layout : NonZeroLayout ) -> Option < Allocation > ;
82+
83+ /// Allocate a block of memory initialized with zeros.
84+ ///
85+ /// The callee guarantees that a successful return contains a pointer that fits the layout
86+ /// requested by the caller and the layout in the struct is the same as requested.
87+ fn alloc_zeroed ( & mut self , layout : NonZeroLayout )
88+ -> Option < Allocation >
89+ {
90+ let allocation = InitialAllocRef :: alloc ( self , layout) ?;
91+ unsafe {
92+ write_bytes ( allocation. ptr . as_ptr ( ) , 0u8 , allocation. layout . size ( ) . into ( ) ) ;
93+ }
94+ Some ( allocation)
95+ }
96+ }
97+
6698impl Allocation {
6799 pub ( crate ) fn from_local ( alloc : crate :: local:: Allocation ) -> Self {
68100 Allocation {
@@ -89,18 +121,18 @@ impl Allocation {
89121unsafe impl < ' rf , T > AllocRef for & ' rf T
90122 where T : LocalAlloc < ' rf >
91123{
92- fn alloc ( & mut self , layout : NonZeroLayout ) -> Option < Allocation > {
93- LocalAlloc :: < ' rf > :: alloc ( * self , layout) . map ( Allocation :: from_local )
124+ unsafe fn alloc_from ( & mut self , _ : Allocation , layout : NonZeroLayout ) -> Option < Allocation > {
125+ InitialAllocRef :: alloc ( self , layout)
94126 }
95127
96- unsafe fn dealloc ( & mut self , alloc : Allocation ) {
97- LocalAlloc :: < ' rf > :: dealloc ( * self , alloc. into_local ( ) )
98- }
99-
100- fn alloc_zeroed ( & mut self , layout : NonZeroLayout )
128+ unsafe fn alloc_zeroed_from ( & mut self , _: Allocation , layout : NonZeroLayout )
101129 -> Option < Allocation >
102130 {
103- LocalAlloc :: < ' rf > :: alloc_zeroed ( * self , layout) . map ( Allocation :: from_local)
131+ InitialAllocRef :: alloc_zeroed ( self , layout)
132+ }
133+
134+ unsafe fn dealloc ( & mut self , alloc : Allocation ) {
135+ LocalAlloc :: < ' rf > :: dealloc ( * self , alloc. into_local ( ) )
104136 }
105137
106138 unsafe fn realloc ( & mut self , alloc : Allocation , layout : NonZeroLayout )
@@ -110,3 +142,15 @@ unsafe impl<'rf, T> AllocRef for &'rf T
110142 . map ( Allocation :: from_local)
111143 }
112144}
145+
146+ unsafe impl < ' rf , T > InitialAllocRef for & ' rf T
147+ where T : LocalAlloc < ' rf >
148+ {
149+ fn alloc ( & mut self , layout : NonZeroLayout ) -> Option < Allocation > {
150+ LocalAlloc :: < ' rf > :: alloc ( * self , layout) . map ( Allocation :: from_local)
151+ }
152+
153+ fn alloc_zeroed ( & mut self , layout : NonZeroLayout ) -> Option < Allocation > {
154+ LocalAlloc :: < ' rf > :: alloc_zeroed ( * self , layout) . map ( Allocation :: from_local)
155+ }
156+ }
0 commit comments