1
1
use core:: ptr:: Unique ;
2
2
use core:: mem:: { self , size_of} ;
3
+ use alloc:: allocator:: { Layout , AllocErr } ;
3
4
4
5
use super :: align_up;
5
6
@@ -41,14 +42,15 @@ impl HoleList {
41
42
}
42
43
43
44
/// Searches the list for a big enough hole. A hole is big enough if it can hold an allocation
44
- /// of `size` bytes with the given `align`. If such a hole is found in the list, a block of the
45
- /// required size is allocated from it. Then the start address of that block is returned.
45
+ /// of `layout.size()` bytes with the given `layout.align()`. If such a hole is found in the
46
+ /// list, a block of the required size is allocated from it. Then the start address of that
47
+ /// block is returned.
46
48
/// This function uses the “first fit” strategy, so it uses the first hole that is big
47
49
/// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations.
48
- pub fn allocate_first_fit ( & mut self , size : usize , align : usize ) -> Option < * mut u8 > {
49
- assert ! ( size >= Self :: min_size( ) ) ;
50
+ pub fn allocate_first_fit ( & mut self , layout : Layout ) -> Result < * mut u8 , AllocErr > {
51
+ assert ! ( layout . size( ) >= Self :: min_size( ) ) ;
50
52
51
- allocate_first_fit ( & mut self . first , size , align ) . map ( |allocation| {
53
+ allocate_first_fit ( & mut self . first , layout ) . map ( |allocation| {
52
54
if let Some ( padding) = allocation. front_padding {
53
55
deallocate ( & mut self . first , padding. addr , padding. size ) ;
54
56
}
@@ -59,14 +61,14 @@ impl HoleList {
59
61
} )
60
62
}
61
63
62
- /// Frees the allocation given by `ptr` and `size `. `ptr` must be a pointer returned by a call
63
- /// to the `allocate_first_fit` function with identical size . Undefined behavior may occur for
64
+ /// Frees the allocation given by `ptr` and `layout `. `ptr` must be a pointer returned by a call
65
+ /// to the `allocate_first_fit` function with identical layout . Undefined behavior may occur for
64
66
/// invalid arguments.
65
67
/// This function walks the list and inserts the given block at the correct place. If the freed
66
68
/// block is adjacent to another free block, the blocks are merged again.
67
69
/// This operation is in `O(n)` since the list needs to be sorted by address.
68
- pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , size : usize ) {
69
- deallocate ( & mut self . first , ptr as usize , size)
70
+ pub unsafe fn deallocate ( & mut self , ptr : * mut u8 , layout : Layout ) {
71
+ deallocate ( & mut self . first , ptr as usize , layout . size ( ) )
70
72
}
71
73
72
74
/// Returns the minimal allocation size. Smaller allocations or deallocations are not allowed.
@@ -125,11 +127,14 @@ struct Allocation {
125
127
}
126
128
127
129
/// Splits the given hole into `(front_padding, hole, back_padding)` if it's big enough to allocate
128
- /// `required_size ` bytes with the `required_align `. Else `None` is returned.
130
+ /// `required_layout.size() ` bytes with the `required_layout.align() `. Else `None` is returned.
129
131
/// Front padding occurs if the required alignment is higher than the hole's alignment. Back
130
132
/// padding occurs if the required size is smaller than the size of the aligned hole. All padding
131
133
/// must be at least `HoleList::min_size()` big or the hole is unusable.
132
- fn split_hole ( hole : HoleInfo , required_size : usize , required_align : usize ) -> Option < Allocation > {
134
+ fn split_hole ( hole : HoleInfo , required_layout : Layout ) -> Option < Allocation > {
135
+ let required_size = required_layout. size ( ) ;
136
+ let required_align = required_layout. align ( ) ;
137
+
133
138
let ( aligned_addr, front_padding) = if hole. addr == align_up ( hole. addr , required_align) {
134
139
// hole has already the required alignment
135
140
( hole. addr , None )
@@ -179,29 +184,32 @@ fn split_hole(hole: HoleInfo, required_size: usize, required_align: usize) -> Op
179
184
}
180
185
181
186
/// Searches the list starting at the next hole of `previous` for a big enough hole. A hole is big
182
- /// enough if it can hold an allocation of `size` bytes with the given `align`. When a hole is used
183
- /// for an allocation, there may be some needed padding before and/or after the allocation. This
184
- /// padding is returned as part of the `Allocation`. The caller must take care of freeing it again.
187
+ /// enough if it can hold an allocation of `layout.size()` bytes with the given `layou.align()`.
188
+ /// When a hole is used for an allocation, there may be some needed padding before and/or after
189
+ /// the allocation. This padding is returned as part of the `Allocation`. The caller must take
190
+ /// care of freeing it again.
185
191
/// This function uses the “first fit” strategy, so it breaks as soon as a big enough hole is
186
192
/// found (and returns it).
187
- fn allocate_first_fit ( mut previous : & mut Hole , size : usize , align : usize ) -> Option < Allocation > {
193
+ fn allocate_first_fit ( mut previous : & mut Hole , layout : Layout ) -> Result < Allocation , AllocErr > {
188
194
loop {
189
195
let allocation: Option < Allocation > = previous. next
190
196
. as_mut ( )
191
- . and_then ( |current| split_hole ( unsafe { current. as_ref ( ) } . info ( ) , size , align ) ) ;
197
+ . and_then ( |current| split_hole ( unsafe { current. as_ref ( ) } . info ( ) , layout . clone ( ) ) ) ;
192
198
match allocation {
193
199
Some ( allocation) => {
194
200
// hole is big enough, so remove it from the list by updating the previous pointer
195
201
previous. next = previous. next_unwrap ( ) . next . take ( ) ;
196
- return Some ( allocation) ;
202
+ return Ok ( allocation) ;
197
203
}
198
204
None if previous. next . is_some ( ) => {
199
205
// try next hole
200
206
previous = move_helper ( previous) . next_unwrap ( ) ;
201
207
}
202
208
None => {
203
209
// this was the last hole, so no hole is big enough -> allocation not possible
204
- return None ;
210
+ return Err ( AllocErr :: Exhausted {
211
+ request : layout,
212
+ } ) ;
205
213
}
206
214
}
207
215
}
0 commit comments