-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathstatic_allocator.rs
More file actions
89 lines (76 loc) · 2.53 KB
/
static_allocator.rs
File metadata and controls
89 lines (76 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use core::{mem::{size_of, align_of}, ptr::NonNull};
pub struct Layout{
size:usize,
align:usize
}
impl Layout{
pub fn new(size:usize)->Self{
let default_align = size_of::<usize>();
Self::with_align(size, default_align)
}
pub fn from_type<T>()->Self{
Self::with_align(size_of::<T>(), align_of::<T>())
}
pub fn with_align(size:usize, align:usize)->Self{
if !Self::is_2_power(align) {
core::panic!("Layout alignment must be a power of 2 but was: {}", align);
}
Self { size, align }
}
fn is_2_power(x:usize)->bool{
(x & (x - 1)) == 0
}
}
pub struct StaticAllocator{
buffer_ptr: *mut u8,
buffer_size: usize,
allocation_size: usize
}
impl StaticAllocator{
pub const fn new(buffer_ptr:*mut u8, buffer_size: usize)->Self{
Self{ buffer_ptr, buffer_size, allocation_size: 0 }
}
pub fn alloc(&mut self, layout: Layout) -> NonNull<u8> {
if self.allocation_size + layout.align + layout.size > self.buffer_size {
core::panic!("Allocation failed, allocator is out of static memory, pool size: {}, allocation req: {}", self.buffer_size, layout.size);
}
let allocation_address = unsafe{self.buffer_ptr.add(self.allocation_size)};
let aligned_address = Self::align_address(allocation_address, layout.align);
self.allocation_size += layout.size + (unsafe{aligned_address.offset_from(allocation_address)} as usize);
return NonNull::new(aligned_address as *mut u8).expect("Null ptr detected");
}
fn align_address(address:*mut u8, alignment:usize)->*mut u8 {
let reminder = address as usize % alignment;
return if reminder != 0 {
unsafe{address.sub(reminder).add(alignment)}
} else {address};
}
}
#[cfg(test)]
mod tests{
use super::*;
#[test]
fn test_alloc_alignment(){
static mut BUFFER:[u8;100] = [0;100];
let mut allocator = unsafe{StaticAllocator::new(BUFFER.as_mut_ptr(), 100)};
let aligns = 5;
for a in 1..aligns{
let align = 1 << a;
let ptr = allocator.alloc(Layout { size: 1, align });
// verify the address is aligned
assert_eq!(ptr.as_ptr() as usize & (align - 1), 0);
}
}
#[test]
fn test_create_layout(){
struct TestType{
_x:u32
}
let _ = Layout::from_type::<TestType>();
}
#[test]
#[should_panic]
fn test_unaligned_layout(){
let _ = Layout::with_align(1, 3);
}
}