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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::alloc::{self, Layout};
/// An object which allocates memory for use.
///
/// # Safety
///
/// The implementor must ensure that `n` is non-zero, and that the pointers returned are the
/// specified size and alignment.
pub unsafe trait Allocator {
/// Allocate an array of `n` items. `n` must not be zero.
///
/// # Arguments
///
/// `n`: The number of array elements
fn allocate<T>(&mut self, n: usize) -> *mut T {
unsafe {
std::mem::transmute(
self.allocate_raw_aligned(n * std::mem::size_of::<T>(), std::mem::align_of::<T>()),
)
}
}
/// Allocate `n` bytes aligned to usize. `n` must not be zero.
///
/// # Arguments
///
/// `n`: The number of bytes to allocate
fn allocate_raw(&mut self, n: usize) -> *mut () {
self.allocate_raw_aligned(n, std::mem::size_of::<usize>())
}
/// Allocate `n` bytes aligned to `align` bytes. `n` must not be zero.
///
/// # Arguments
///
/// `n`: The number of bytes to allocate
///
/// `align`: The alignment of the block to allocate
fn allocate_raw_aligned(&mut self, n: usize, align: usize) -> *mut ();
/// Deallocates the block `p` of size `n` bytes aligned to usize and returns it to
/// available memory to re-allocate
///
/// # Safety
///
/// `p` must be a valid pointer to an array with size `n`.
unsafe fn deallocate<T>(&mut self, p: *mut T, n: usize) {
self.deallocate_raw_aligned(
std::mem::transmute::<*mut T, *mut ()>(p),
n * std::mem::size_of::<T>(),
std::mem::align_of::<T>(),
)
}
/// Deallocates the block `p` of size `n` bytes aligned to usize and returns it to
/// available memory to re-allocate
///
/// # Arguments
///
/// `p`: The pointer to the block of memory
///
/// `n`: The number of bytes to deallocate
///
/// # Safety
///
/// `p` must be a valid pointer
unsafe fn deallocate_raw(&mut self, p: *mut (), n: usize) {
self.deallocate_raw_aligned(p, n, std::mem::size_of::<usize>())
}
/// Deallocates the block `p` of size `n` bytes and returns it to
/// available memory to re-allocate
///
/// # Arguments
///
/// `p`: The pointer to the block of memory
///
/// `n`: The number of bytes to deallocate
///
/// `align`: The alignment of the block of memory
///
/// # Safety
///
/// `p` must be a valid pointer
unsafe fn deallocate_raw_aligned(&mut self, p: *mut (), n: usize, align: usize);
}
#[derive(Default)]
#[repr(C)]
pub struct DefaultAllocator {
// padding due to 1-size struct in C
_dummy: u8,
}
impl DefaultAllocator {
pub const fn new() -> Self {
Self { _dummy: 0 }
}
}
unsafe impl Allocator for DefaultAllocator {
fn allocate_raw_aligned(&mut self, n: usize, align: usize) -> *mut () {
assert_ne!(n, 0, "`n` must not be zero!");
unsafe {
std::mem::transmute(alloc::alloc(
Layout::array::<u8>(n).unwrap().align_to(align).unwrap(),
))
}
}
unsafe fn deallocate_raw_aligned(&mut self, p: *mut (), n: usize, align: usize) {
alloc::dealloc(
std::mem::transmute::<*mut (), *mut u8>(p),
Layout::array::<u8>(n).unwrap().align_to(align).unwrap(),
)
}
}
#[cfg(test)]
mod test {
use super::{Allocator, DefaultAllocator};
#[test]
fn layout() {
assert_eq!(
std::mem::size_of::<DefaultAllocator>(),
std::mem::size_of::<u8>()
)
}
#[test]
fn align() {
let mut alloc = DefaultAllocator::default();
let aligned_by_4 = alloc.allocate_raw_aligned(20, 4);
unsafe { alloc.deallocate_raw_aligned(aligned_by_4, 20, 4) };
let aligned_by_8 = alloc.allocate_raw_aligned(20, 8);
unsafe { alloc.deallocate_raw_aligned(aligned_by_8, 20, 8) };
let aligned_by_16 = alloc.allocate_raw_aligned(20, 16);
unsafe { alloc.deallocate_raw_aligned(aligned_by_16, 20, 16) };
assert_eq!((aligned_by_4 as usize) % 4, 0);
assert_eq!((aligned_by_8 as usize) % 8, 0);
assert_eq!((aligned_by_16 as usize) % 16, 0);
}
}