customizable_buddy/
linked_list.rs1use crate::{BuddyCollection, BuddyLine, OligarchyCollection, Order};
2use core::{fmt, ptr::NonNull};
3
4pub struct LinkedListBuddy {
9 free_list: Node,
11 order: Order,
13}
14
15unsafe impl Send for LinkedListBuddy {}
17
18impl BuddyLine for LinkedListBuddy {
19 const INTRUSIVE_META_SIZE: usize = core::mem::size_of::<Node>();
20
21 const EMPTY: Self = Self {
22 free_list: Node { next: None },
23 order: Order::new(0),
24 };
25
26 #[inline]
27 fn init(&mut self, order: usize, _base: usize) {
28 self.order = Order::new(order);
29 }
30
31 fn take(&mut self, _idx: usize) -> bool {
32 todo!("not efficient")
33 }
34}
35
36impl OligarchyCollection for LinkedListBuddy {
37 #[inline]
38 fn take_any(&mut self, align_order: usize, count: usize) -> Option<usize> {
39 if count > 1 || align_order > 0 {
40 None
42 } else {
43 self.free_list
45 .take_any()
46 .map(|ptr| self.order.ptr_to_idx(ptr))
47 }
48 }
49
50 #[inline]
52 fn put(&mut self, idx: usize) {
53 let ptr = self.order.idx_to_ptr(idx).expect("block address is null");
54 self.free_list.insert_unordered(ptr);
55 }
56}
57
58impl BuddyCollection for LinkedListBuddy {
59 #[inline]
60 fn take_any(&mut self, align_order: usize) -> Option<usize> {
61 if align_order != 0 {
62 None
64 } else {
65 self.free_list
66 .take_any()
67 .map(|ptr| self.order.ptr_to_idx(ptr))
68 }
69 }
70
71 fn put(&mut self, idx: usize) -> Option<usize> {
73 let node = self.order.idx_to_ptr(idx).expect("block address is null");
75 let Some(buddy) = self.order.idx_to_ptr(idx ^ 1) else {
77 self.free_list.insert_unordered(node);
78 return None;
79 };
80 if self.free_list.insert(node, buddy) {
81 None
82 } else {
83 Some(idx >> 1)
85 }
86 }
87}
88
89impl fmt::Debug for LinkedListBuddy {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "[")?;
92 let mut cursor = &self.free_list;
93 while let Some(next) = cursor.next {
94 write!(f, "{:#x}, ", self.order.ptr_to_idx(next))?;
95 cursor = unsafe { next.as_ref() };
96 }
97 write!(f, "]")
98 }
99}
100
101#[repr(transparent)]
105struct Node {
106 next: Option<NonNull<Node>>,
108}
109
110impl Node {
111 #[inline]
118 fn insert(&mut self, mut node: NonNull<Node>, buddy: NonNull<Node>) -> bool {
119 let mut cursor = self;
120 loop {
121 if let Some(mut next) = cursor.next {
122 use core::cmp::Ordering::*;
123 match next.cmp(&buddy) {
124 Less => cursor = unsafe { next.as_mut() },
126 Equal => {
128 cursor.next = unsafe { next.as_ref().next };
129 unsafe { node.as_mut() }.next = None;
130 break false;
131 }
132 Greater => {
134 cursor.next = Some(node);
135 unsafe { node.as_mut() }.next = Some(next);
136 break true;
137 }
138 }
139 } else {
140 cursor.next = Some(node);
142 unsafe { node.as_mut() }.next = None;
143 break true;
144 }
145 }
146 }
147
148 #[inline]
150 fn insert_unordered(&mut self, mut node: NonNull<Node>) {
151 unsafe { node.as_mut() }.next = self.next.replace(node);
152 }
153
154 #[inline]
156 fn take_any(&mut self) -> Option<NonNull<Node>> {
157 let root = self.next;
158 self.next = root.and_then(|node| unsafe { node.as_ref().next });
159 root
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[repr(C, align(16))]
169 struct TestMemory {
170 data: [u8; 256],
171 }
172
173 #[test]
174 fn test_empty() {
175 let list = LinkedListBuddy::EMPTY;
176 assert!(list.free_list.next.is_none());
177 }
178
179 #[test]
180 fn test_init() {
181 let mut list = LinkedListBuddy::EMPTY;
182 list.init(3, 0);
183 assert_eq!(list.order.0, 3);
185 }
186
187 #[test]
188 fn test_insert_unordered() {
189 let mut list = LinkedListBuddy::EMPTY;
190 list.init(4, 0); let mut memory = TestMemory { data: [0; 256] };
194 let node_ptr = NonNull::new(memory.data.as_mut_ptr().cast::<Node>()).unwrap();
195
196 let idx = list.order.ptr_to_idx(node_ptr);
198 OligarchyCollection::put(&mut list, idx);
199
200 assert!(list.free_list.next.is_some());
202 }
203
204 #[test]
205 fn test_take_and_put_buddy() {
206 let mut list = LinkedListBuddy::EMPTY;
207 list.init(4, 0); let mut memory = TestMemory { data: [0; 256] };
211 let node_ptr = NonNull::new(memory.data.as_mut_ptr().cast::<Node>()).unwrap();
212
213 let idx = list.order.ptr_to_idx(node_ptr);
215 OligarchyCollection::put(&mut list, idx);
216
217 let taken_idx = OligarchyCollection::take_any(&mut list, 0, 1);
219 assert_eq!(taken_idx, Some(idx));
220 }
221
222 #[test]
223 fn test_buddy_merge() {
224 let mut list = LinkedListBuddy::EMPTY;
225 list.init(4, 0); let mut memory = TestMemory { data: [0; 256] };
229 let base = memory.data.as_mut_ptr() as usize;
230 let ptr0 = (base + 15) & !15; let idx0 = ptr0 >> 4;
235
236 let idx0 = idx0 & !1; let idx1 = idx0 ^ 1; OligarchyCollection::put(&mut list, idx0);
242 let result = BuddyCollection::put(&mut list, idx1);
244 assert_eq!(result, Some(idx0 >> 1));
246 }
247
248 #[test]
249 fn test_buddy_collection_take_any() {
250 let mut list = LinkedListBuddy::EMPTY;
251 list.init(0, 0);
252
253 assert_eq!(BuddyCollection::take_any(&mut list, 0), None);
255
256 assert_eq!(BuddyCollection::take_any(&mut list, 1), None);
258 }
259
260 #[test]
261 fn test_oligarchy_collection_take_any() {
262 let mut list = LinkedListBuddy::EMPTY;
263 list.init(0, 0);
264
265 assert_eq!(OligarchyCollection::take_any(&mut list, 0, 2), None);
267 assert_eq!(OligarchyCollection::take_any(&mut list, 1, 1), None);
269 }
270
271 #[test]
272 fn test_node_insert() {
273 let mut head = Node { next: None };
275
276 let mut memory = TestMemory { data: [0; 256] };
277 let ptr1 = NonNull::new(memory.data.as_mut_ptr().cast::<Node>()).unwrap();
278 let ptr2 = NonNull::new(memory.data.as_mut_ptr().wrapping_add(16).cast::<Node>()).unwrap();
279 let ptr3 = NonNull::new(memory.data.as_mut_ptr().wrapping_add(32).cast::<Node>()).unwrap();
280
281 head.insert_unordered(ptr1);
283 assert!(head.next.is_some());
284
285 head.insert_unordered(ptr2);
287
288 let buddy = NonNull::new(memory.data.as_mut_ptr().wrapping_add(64).cast::<Node>()).unwrap();
290 assert!(head.insert(ptr3, buddy));
291 }
292
293 #[test]
294 fn test_node_take_any() {
295 let mut head = Node { next: None };
296
297 let mut memory = TestMemory { data: [0; 256] };
298 let ptr = NonNull::new(memory.data.as_mut_ptr().cast::<Node>()).unwrap();
299
300 head.insert_unordered(ptr);
301
302 let taken = head.take_any();
304 assert!(taken.is_some());
305
306 assert!(head.take_any().is_none());
308 }
309}