@@ -4,65 +4,97 @@ use crate::NonZeroLayout;
4
4
use crate :: LocalAlloc ;
5
5
6
6
/// An allocation without tracked lifetime.
7
+ #[ derive( Copy , Clone ) ]
7
8
pub struct Allocation {
8
9
ptr : NonNull < u8 > ,
9
10
layout : NonZeroLayout ,
10
11
}
11
12
12
13
/// A references to an allocator.
13
14
///
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.
17
24
///
18
25
/// [`LocalAlloc`]: trait.LocalAlloc.html
19
26
pub unsafe trait AllocRef {
20
27
/// Allocate one block of memory.
21
28
///
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 > ;
32
35
33
36
/// Allocate a block of memory initialized with zeros.
34
37
///
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 )
39
41
-> Option < Allocation >
40
42
{
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 ( ) ) ;
45
45
Some ( allocation)
46
46
}
47
47
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
+
48
55
/// Change the layout of a block previously allocated.
49
56
///
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.
54
62
unsafe fn realloc ( & mut self , alloc : Allocation , layout : NonZeroLayout )
55
63
-> Option < Allocation >
56
64
{
57
- let new_alloc = self . alloc ( layout) ?;
65
+ let new_alloc = self . alloc_from ( alloc , layout) ?;
58
66
copy_nonoverlapping (
59
67
alloc. ptr . as_ptr ( ) ,
60
68
new_alloc. ptr . as_ptr ( ) ,
61
69
layout. size ( ) . min ( alloc. layout . size ( ) ) . into ( ) ) ;
70
+ self . dealloc ( alloc) ;
62
71
Some ( new_alloc)
63
72
}
64
73
}
65
74
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
+
66
98
impl Allocation {
67
99
pub ( crate ) fn from_local ( alloc : crate :: local:: Allocation ) -> Self {
68
100
Allocation {
@@ -89,18 +121,18 @@ impl Allocation {
89
121
unsafe impl < ' rf , T > AllocRef for & ' rf T
90
122
where T : LocalAlloc < ' rf >
91
123
{
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)
94
126
}
95
127
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 )
101
129
-> Option < Allocation >
102
130
{
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 ( ) )
104
136
}
105
137
106
138
unsafe fn realloc ( & mut self , alloc : Allocation , layout : NonZeroLayout )
@@ -110,3 +142,15 @@ unsafe impl<'rf, T> AllocRef for &'rf T
110
142
. map ( Allocation :: from_local)
111
143
}
112
144
}
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