Skip to main content

customizable_buddy/
lib.rs

1//! 伙伴分配器。
2
3#![no_std]
4#![deny(warnings, unstable_features, missing_docs)]
5
6mod avl;
7mod bitmap;
8mod linked_list;
9
10pub use avl::AvlBuddy;
11pub use bitmap::UsizeBuddy;
12pub use linked_list::LinkedListBuddy;
13
14use core::{alloc::Layout, fmt, num::NonZeroUsize, ptr::NonNull};
15
16/// 伙伴分配器的一个行。
17pub trait BuddyLine {
18    /// 空集合。用于静态初始化。
19    const EMPTY: Self;
20
21    /// 侵入式元数据的大小。
22    const INTRUSIVE_META_SIZE: usize = 0;
23
24    /// 伙伴分配器可能需要集合知道自己的阶数和基序号。
25    #[inline]
26    fn init(&mut self, _order: usize, _base: usize) {}
27
28    /// 提取指定位置的元素,返回是否提取到。
29    #[inline]
30    fn take(&mut self, _idx: usize) -> bool {
31        unimplemented!()
32    }
33}
34
35/// 寡头集合。伙伴分配器的顶层,不再合并。
36pub trait OligarchyCollection: BuddyLine {
37    /// 提取任何 `count` 个满足 `align_order` 的内存块。
38    ///
39    /// 返回提取到第一个元素的序号。若找不到连续的那么多块,返回 [`None`]。
40    fn take_any(&mut self, align_order: usize, count: usize) -> Option<usize>;
41
42    /// 放入一个元素 `idx`。
43    fn put(&mut self, idx: usize);
44}
45
46/// 伙伴集合。一组同阶的伙伴。
47pub trait BuddyCollection: BuddyLine {
48    /// 提取任何一个满足 `align_order` 的内存块。
49    ///
50    /// 返回提取到的元素。若集合为空则无法提取,返回 [`None`]。
51    fn take_any(&mut self, align_order: usize) -> Option<usize>;
52
53    /// 放入一个元素 `idx`。
54    ///
55    /// 如果 `idx` 的伙伴元素存在,则两个元素都被提取并返回他们在上一层的序号。
56    /// 否则 `idx` 被放入集合。
57    fn put(&mut self, idx: usize) -> Option<usize>;
58}
59
60/// 伙伴分配器分配失败。
61#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62#[repr(transparent)]
63pub struct BuddyError;
64
65/// 伙伴分配器。
66pub struct BuddyAllocator<const N: usize, O: OligarchyCollection, B: BuddyCollection> {
67    /// 寡头集合,管理最大阶数的内存块。
68    oligarchy: O,
69
70    /// `N` 阶 `B` 型伙伴集合。
71    /// `buddies[i]` 管理阶数为 `min_order + i` 的内存块。
72    buddies: [B; N],
73
74    /// 最小阶数。
75    ///
76    /// `buddies[0]` 伙伴行分配的内存块的阶数。
77    min_order: usize,
78
79    /// 空闲容量(字节)。
80    free: usize,
81
82    /// 总容量(字节)。
83    capacity: usize,
84}
85
86impl<const N: usize, O: OligarchyCollection, B: BuddyCollection> BuddyAllocator<N, O, B> {
87    /// 最大层数。
88    const MAX_LAYER: usize = N;
89    /// 寡头支持的最小阶数。
90    const O_MIN_ORDER: usize = O::INTRUSIVE_META_SIZE.next_power_of_two().trailing_zeros() as _;
91    /// 伙伴支持的最小阶数。
92    const B_MIN_ORDER: usize = B::INTRUSIVE_META_SIZE.next_power_of_two().trailing_zeros() as _;
93
94    /// 构造分配器。
95    #[inline]
96    pub const fn new() -> Self {
97        Self {
98            oligarchy: O::EMPTY,
99            buddies: [B::EMPTY; N],
100            min_order: 0,
101            free: 0,
102            capacity: 0,
103        }
104    }
105}
106
107impl<const N: usize, O: OligarchyCollection, B: BuddyCollection> Default
108    for BuddyAllocator<N, O, B>
109{
110    fn default() -> Self {
111        Self::new()
112    }
113}
114
115impl<const N: usize, O: OligarchyCollection, B: BuddyCollection> BuddyAllocator<N, O, B> {
116    /// 返回分配器管理的总容量。
117    #[inline]
118    pub fn capacity(&self) -> usize {
119        self.capacity
120    }
121
122    /// 返回分配器剩余的空间容量。
123    #[inline]
124    pub fn free(&self) -> usize {
125        self.free
126    }
127
128    /// 最大阶数。寡头块的阶数。
129    #[inline]
130    const fn max_order(&self) -> usize {
131        self.min_order + Self::MAX_LAYER
132    }
133
134    /// 运行时初始化。
135    ///
136    /// 设置分配器分配的最小阶数和基址。
137    #[inline]
138    pub fn init<T>(&mut self, min_order: usize, base: NonNull<T>) {
139        assert_eq!(
140            0, self.capacity,
141            "init is not allowed after any transfering"
142        );
143
144        self.min_order = min_order;
145        let max_order = self.max_order();
146
147        assert!(Self::O_MIN_ORDER <= max_order);
148        assert!(Self::B_MIN_ORDER <= min_order);
149
150        let base = base.as_ptr() as usize;
151        self.buddies.iter_mut().enumerate().for_each(|(i, c)| {
152            let o = self.min_order + i;
153            c.init(o, base >> o)
154        });
155        self.oligarchy.init(max_order, base >> max_order);
156    }
157
158    /// 将一个 `ptr` 指向的长度为 `usize` 的内存块转移给分配器。
159    ///
160    /// # Safety
161    ///
162    /// 调用者需要保证:
163    ///
164    /// - 这个内存块没有被其他任何对象引用;
165    /// - 这个内存块和已经托管的内存块不重叠。
166    #[inline]
167    pub unsafe fn transfer<T>(&mut self, ptr: NonNull<T>, size: usize) {
168        self.capacity += size;
169        self.deallocate(ptr, size)
170    }
171
172    /// 从分配器夺走一个对齐到 `align_order` 阶,长度为 `size` 的内存块。
173    #[inline]
174    pub fn snatch<T>(
175        &mut self,
176        align_order: usize,
177        size: NonZeroUsize,
178    ) -> Result<(NonNull<T>, usize), BuddyError> {
179        let ans = self.allocate(align_order, size);
180        if let Ok((_, size)) = ans {
181            self.capacity -= size;
182        }
183        ans
184    }
185
186    /// 分配可容纳 `T` 对象的内存块。
187    #[inline]
188    pub fn allocate_type<T>(&mut self) -> Result<(NonNull<T>, usize), BuddyError> {
189        self.allocate_layout(Layout::new::<T>())
190    }
191
192    /// 分配符合 `layout` 布局的内存块。
193    #[inline]
194    pub fn allocate_layout<T>(
195        &mut self,
196        layout: Layout,
197    ) -> Result<(NonNull<T>, usize), BuddyError> {
198        #[inline]
199        const fn allocated<T, U>(ptr: *mut T, size: usize) -> (NonNull<U>, usize) {
200            (unsafe { NonNull::new_unchecked(ptr) }.cast(), size)
201        }
202
203        if let Some(size) = NonZeroUsize::new(layout.size()) {
204            self.allocate(layout.align().trailing_zeros() as _, size)
205        } else {
206            Ok(allocated(self, 0))
207        }
208    }
209
210    /// 分配。
211    ///
212    /// 如果分配成功,返回一个 `(指针, 长度)` 二元组。
213    pub fn allocate<T>(
214        &mut self,
215        align_order: usize,
216        size: NonZeroUsize,
217    ) -> Result<(NonNull<T>, usize), BuddyError> {
218        let max_order = self.max_order();
219        #[inline]
220        const fn allocated<T, U>(ptr: *mut T, size: usize) -> (NonNull<U>, usize) {
221            (unsafe { NonNull::new_unchecked(ptr) }.cast(), size)
222        }
223
224        // 要分配的容量
225        let page_mask = (1usize << self.min_order) - 1;
226        let ans_size = (size.get() + page_mask) & !page_mask;
227        // 分配的阶数
228        let size_order = nonzero(ans_size.next_power_of_two()).trailing_zeros() as usize;
229        // 分配
230        let (ptr, alloc_size) = if size_order >= max_order {
231            // 连续分配寡头
232            let count = ((ans_size >> (max_order - 1)) + 1) >> 1;
233            let align_offset = align_order.saturating_sub(max_order);
234            match self.oligarchy.take_any(align_offset, count) {
235                Some(idx) => (idx << max_order, count << max_order),
236                None => Err(BuddyError)?,
237            }
238        } else {
239            // 分配伙伴
240            let layer0 = size_order - self.min_order;
241            let mut layer = layer0;
242            let mut idx = loop {
243                // 从寡头借
244                if layer == Self::MAX_LAYER {
245                    let align_offset = align_order.saturating_sub(max_order);
246                    match self.oligarchy.take_any(align_offset, 1) {
247                        Some(idx) => break idx,
248                        None => Err(BuddyError)?,
249                    }
250                }
251                // 从伙伴借
252                let align_offset = align_order.saturating_sub(self.min_order + layer);
253                match self.buddies[layer].take_any(align_offset) {
254                    Some(idx) => break idx,
255                    None => layer += 1,
256                }
257            };
258            // 存回多借用的
259            assert!(self.buddies[layer0..layer].iter_mut().rev().all(|b| {
260                idx <<= 1;
261                b.put(idx + 1).is_none()
262            }));
263            // 完成
264            (idx << size_order, 1 << size_order)
265        };
266        self.free -= alloc_size;
267        // 存回为了对齐而多分配的
268        if alloc_size > ans_size {
269            self.deallocate(
270                unsafe { NonNull::new_unchecked((ptr + ans_size) as *mut u8) },
271                alloc_size - ans_size,
272            );
273        }
274        Ok(allocated(ptr as *mut (), ans_size))
275    }
276
277    /// 根据布局回收。
278    ///
279    /// # Safety
280    ///
281    /// 这个方法认为 `ptr` 是根据 `layout` 分配出来的,
282    /// 因此长度不小于 `layout.size()` 并且对齐到 `self.min_order`。
283    pub unsafe fn deallocate_layout<T>(&mut self, ptr: NonNull<T>, layout: Layout) {
284        debug_assert!((1 << (ptr.as_ptr() as usize).trailing_zeros()) >= layout.align());
285
286        let mask = (1 << self.min_order) - 1;
287        self.deallocate(ptr, (layout.size() + mask) & !mask)
288    }
289
290    /// 回收。
291    ///
292    /// # Notice
293    ///
294    /// 调用者需要保证 `size` 对齐了分配器的最小阶数。
295    pub fn deallocate<T>(&mut self, ptr: NonNull<T>, size: usize) {
296        debug_assert!(
297            size.trailing_zeros() as usize >= self.min_order,
298            "size must align to minium order"
299        );
300
301        let max_order = self.max_order();
302
303        let mut ptr = ptr.as_ptr() as usize;
304        let end = ptr + size;
305        while ptr < end {
306            // 剩余长度
307            let len = nonzero(end - ptr);
308            // 指针的对齐决定最大阶数
309            let order_ptr = nonzero(ptr).trailing_zeros();
310            // 长度向下取整也决定最大阶数
311            let order_len = usize::BITS - len.leading_zeros() - 1;
312            // 实际阶数是两个最大阶数中较小的那个
313            let order = order_ptr.min(order_len) as usize;
314            // 直接释放寡头
315            if order >= max_order {
316                // 寡头序号
317                let idx = ptr >> max_order;
318                // 寡头数量
319                let count = len.get() >> max_order;
320                // 移动指针
321                ptr += count << max_order;
322                // 释放
323                (idx..).take(count).for_each(|idx| self.oligarchy.put(idx));
324            } else {
325                // 伙伴序号
326                let mut idx = ptr >> order;
327                // 移动指针
328                ptr += 1 << order;
329                // 释放
330                for layer in (order - self.min_order).. {
331                    // 释放寡头
332                    if layer == Self::MAX_LAYER {
333                        self.oligarchy.put(idx);
334                        break;
335                    }
336                    // 释放伙伴
337                    match self.buddies[layer].put(idx) {
338                        Some(parent) => idx = parent,
339                        None => break,
340                    }
341                }
342            }
343        }
344        self.free += size;
345        assert!(
346            self.free <= self.capacity,
347            "something wrong with the free bytes, it is larger than the capacity: {} > {}",
348            self.free,
349            self.capacity
350        );
351    }
352}
353
354impl<const N: usize, O: OligarchyCollection + fmt::Debug, B: BuddyCollection + fmt::Debug>
355    fmt::Debug for BuddyAllocator<N, O, B>
356{
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        writeln!(f, "BuddyAllocator@{:#018x}", self as *const _ as usize)?;
359        writeln!(f, "---------------------------------")?;
360        for (i, line) in self.buddies.iter().enumerate() {
361            writeln!(f, "{:>2}> {line:?}", self.min_order + i)?;
362        }
363        writeln!(f, "{:>2}> {:?}", self.max_order(), self.oligarchy)
364    }
365}
366
367#[inline]
368const fn nonzero(val: usize) -> NonZeroUsize {
369    unsafe { NonZeroUsize::new_unchecked(val) }
370}
371
372/// 阶数。
373///
374/// 用于侵入式行序号到指针的转换。
375struct Order(usize);
376
377impl Order {
378    #[inline]
379    const fn new(order: usize) -> Self {
380        Self(order)
381    }
382
383    #[inline]
384    fn idx_to_ptr<T>(&self, idx: usize) -> Option<NonNull<T>> {
385        NonNull::new((idx << self.0) as *mut _)
386    }
387
388    #[inline]
389    fn ptr_to_idx<T>(&self, ptr: NonNull<T>) -> usize {
390        (ptr.as_ptr() as usize) >> self.0
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::*;
397    use crate::{LinkedListBuddy, UsizeBuddy};
398
399    // 定义测试用的分配器类型
400    type TestAllocator<const N: usize> = BuddyAllocator<N, UsizeBuddy, LinkedListBuddy>;
401
402    /// 测试内存区域,用于模拟堆内存
403    #[repr(C, align(4096))]
404    #[derive(Clone, Copy)]
405    struct TestPage([u8; 4096]);
406
407    static mut TEST_MEMORY: [TestPage; 16] = [TestPage([0; 4096]); 16];
408
409    #[test]
410    fn test_allocator_new() {
411        let allocator: TestAllocator<4> = BuddyAllocator::new();
412        assert_eq!(allocator.capacity(), 0);
413        assert_eq!(allocator.free(), 0);
414        assert_eq!(allocator.min_order, 0);
415    }
416
417    #[test]
418    fn test_allocator_default() {
419        let allocator: TestAllocator<4> = BuddyAllocator::default();
420        assert_eq!(allocator.capacity(), 0);
421        assert_eq!(allocator.free(), 0);
422    }
423
424    #[test]
425    fn test_allocator_init() {
426        let mut allocator: TestAllocator<4> = BuddyAllocator::new();
427
428        // 获取测试内存地址
429        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
430
431        allocator.init(12, ptr);
432        assert_eq!(allocator.min_order, 12);
433        assert_eq!(allocator.capacity(), 0);
434        assert_eq!(allocator.free(), 0);
435    }
436
437    #[test]
438    fn test_allocator_transfer() {
439        let mut allocator: TestAllocator<4> = BuddyAllocator::new();
440
441        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
442        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
443
444        allocator.init(12, ptr);
445
446        // 转移内存给分配器
447        unsafe {
448            allocator.transfer(ptr, len);
449        }
450
451        assert_eq!(allocator.capacity(), len);
452        assert_eq!(allocator.free(), len);
453    }
454
455    #[test]
456    fn test_allocator_allocate_deallocate_basic() {
457        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
458
459        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
460        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
461
462        allocator.init(12, ptr);
463        unsafe {
464            allocator.transfer(ptr, len);
465        }
466
467        let initial_free = allocator.free();
468
469        // 分配一个 4KB 的块
470        let size = NonZeroUsize::new(4096).unwrap();
471        let (alloc_ptr, alloc_size) = allocator.allocate::<u8>(0, size).unwrap();
472
473        // 验证分配成功
474        assert!(alloc_size >= 4096);
475        assert!(allocator.free() < initial_free);
476
477        // 释放内存
478        allocator.deallocate(alloc_ptr, alloc_size);
479
480        // 验证释放后空闲空间恢复
481        assert_eq!(allocator.free(), initial_free);
482    }
483
484    #[test]
485    fn test_allocator_allocate_type() {
486        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
487
488        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
489        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
490
491        allocator.init(12, ptr);
492        unsafe {
493            allocator.transfer(ptr, len);
494        }
495
496        let initial_free = allocator.free();
497
498        // 分配一个 usize 大小的内存
499        let (alloc_ptr, alloc_size) = allocator.allocate_type::<usize>().unwrap();
500
501        // 验证分配成功
502        assert!(alloc_size >= core::mem::size_of::<usize>());
503
504        // 释放内存
505        allocator.deallocate(alloc_ptr, alloc_size);
506
507        assert_eq!(allocator.free(), initial_free);
508    }
509
510    #[test]
511    fn test_allocator_allocate_layout() {
512        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
513
514        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
515        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
516
517        allocator.init(12, ptr);
518        unsafe {
519            allocator.transfer(ptr, len);
520        }
521
522        let initial_free = allocator.free();
523
524        // 创建一个对齐要求为 8 的 layout
525        let layout = Layout::from_size_align(64, 8).unwrap();
526        let (alloc_ptr, alloc_size) = allocator.allocate_layout::<u8>(layout).unwrap();
527
528        // 验证分配成功
529        assert!(alloc_size >= 64);
530
531        // 释放内存
532        unsafe {
533            allocator.deallocate_layout(alloc_ptr, layout);
534        }
535
536        assert_eq!(allocator.free(), initial_free);
537    }
538
539    #[test]
540    fn test_allocator_multiple_allocations() {
541        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
542
543        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
544        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
545
546        allocator.init(12, ptr);
547        unsafe {
548            allocator.transfer(ptr, len);
549        }
550
551        let initial_free = allocator.free();
552
553        // 分配多个内存块
554        let size1 = NonZeroUsize::new(1024).unwrap();
555        let size2 = NonZeroUsize::new(2048).unwrap();
556        let size3 = NonZeroUsize::new(4096).unwrap();
557
558        let (ptr1, size1) = allocator.allocate::<u8>(0, size1).unwrap();
559        let (ptr2, size2) = allocator.allocate::<u8>(0, size2).unwrap();
560        let (ptr3, size3) = allocator.allocate::<u8>(0, size3).unwrap();
561
562        // 释放其中一个
563        allocator.deallocate(ptr2, size2);
564
565        // 释放剩余
566        allocator.deallocate(ptr1, size1);
567        allocator.deallocate(ptr3, size3);
568
569        assert_eq!(allocator.free(), initial_free);
570    }
571
572    #[test]
573    fn test_allocator_snatch() {
574        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
575
576        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
577        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
578
579        allocator.init(12, ptr);
580        unsafe {
581            allocator.transfer(ptr, len);
582        }
583
584        let initial_capacity = allocator.capacity();
585        let initial_free = allocator.free();
586
587        // 使用 snatch 分配内存,这会减少 capacity
588        let size = NonZeroUsize::new(4096).unwrap();
589        let (_alloc_ptr, alloc_size) = allocator.snatch::<u8>(0, size).unwrap();
590
591        // snatch 会减少 capacity 和 free
592        assert!(allocator.capacity() < initial_capacity);
593        assert_eq!(allocator.capacity(), initial_capacity - alloc_size);
594        assert_eq!(allocator.free(), initial_free - alloc_size);
595
596        // 注意:snatch 后不应该调用 deallocate,因为这会导致 free > capacity
597        // 这是 snatch 的语义:永久夺取内存,不再归还
598    }
599
600    #[test]
601    fn test_allocator_allocate_failure() {
602        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
603
604        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
605        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
606
607        allocator.init(12, ptr);
608        unsafe {
609            allocator.transfer(ptr, len);
610        }
611
612        // 尝试分配一个超过容量的块(应该失败)
613        // 使用一个合理的大值,避免溢出
614        let huge_size = NonZeroUsize::new(len * 2).unwrap();
615        assert!(allocator.allocate::<u8>(0, huge_size).is_err());
616    }
617
618    #[test]
619    fn test_allocator_zero_size_allocation() {
620        let mut allocator: TestAllocator<8> = BuddyAllocator::new();
621
622        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
623        let len = core::mem::size_of_val(unsafe { &*core::ptr::addr_of!(TEST_MEMORY) });
624
625        allocator.init(12, ptr);
626        unsafe {
627            allocator.transfer(ptr, len);
628        }
629
630        // 使用 allocate_layout 分配零大小
631        let layout = Layout::from_size_align(0, 1).unwrap();
632        let (_alloc_ptr, alloc_size) = allocator.allocate_layout::<u8>(layout).unwrap();
633
634        // 零大小分配应该返回非空指针但大小为 0
635        assert_eq!(alloc_size, 0);
636    }
637
638    #[test]
639    fn test_max_order() {
640        let mut allocator: TestAllocator<4> = BuddyAllocator::new();
641
642        let ptr = NonNull::new(core::ptr::addr_of_mut!(TEST_MEMORY).cast::<u8>()).unwrap();
643
644        allocator.init(3, ptr);
645
646        // max_order = min_order + MAX_LAYER = 3 + 4 = 7
647        assert_eq!(allocator.max_order(), 7);
648    }
649
650    #[test]
651    fn test_order_idx_to_ptr() {
652        let order = Order::new(12);
653
654        // 测试 idx 到 ptr 的转换
655        // idx=0 对应空指针,返回 None
656        assert!(order.idx_to_ptr::<u8>(0).is_none());
657        let ptr = order.idx_to_ptr::<u8>(1).unwrap();
658        assert_eq!(ptr.as_ptr() as usize, 4096); // 1 << 12
659
660        let ptr = order.idx_to_ptr::<u8>(2).unwrap();
661        assert_eq!(ptr.as_ptr() as usize, 8192); // 2 << 12
662
663        let ptr = order.idx_to_ptr::<u8>(3).unwrap();
664        assert_eq!(ptr.as_ptr() as usize, 12288); // 3 << 12
665    }
666
667    #[test]
668    fn test_order_ptr_to_idx() {
669        let order = Order::new(12);
670
671        // 测试 ptr 到 idx 的转换
672        let ptr = NonNull::new(4096 as *mut u8).unwrap();
673        assert_eq!(order.ptr_to_idx(ptr), 1);
674
675        let ptr = NonNull::new(8192 as *mut u8).unwrap();
676        assert_eq!(order.ptr_to_idx(ptr), 2);
677    }
678
679    #[test]
680    fn test_order_roundtrip() {
681        let order = Order::new(12);
682
683        // 测试 idx -> ptr -> idx 的往返转换
684        // idx=0 会生成空指针,所以从 1 开始
685        for i in [1, 5, 100, 1000] {
686            let ptr = order.idx_to_ptr::<u8>(i).unwrap();
687            let idx = order.ptr_to_idx(ptr);
688            assert_eq!(idx, i);
689        }
690    }
691
692    /// 回归测试:低地址缓冲区跨越 2 的幂次边界时,buddy序号为 0 导致空指针。
693    #[test]
694    fn test_transfer_low_address_crossing_boundary() {
695        #[repr(C, align(4096))]
696        struct Buf {
697            _data: [u8; 128 * 1024],
698        }
699        static mut BUF: Buf = Buf {
700            _data: [0; 128 * 1024],
701        };
702
703        type A = BuddyAllocator<32, UsizeBuddy, LinkedListBuddy>;
704        let mut alloc = A::new();
705
706        let ptr = NonNull::new((&raw mut BUF).cast::<u8>()).unwrap();
707        let len = 128 * 1024;
708
709        alloc.init(3, ptr);
710        unsafe { alloc.transfer(ptr, len) };
711
712        let size = NonZeroUsize::new(4096).unwrap();
713        let (p, s) = alloc.allocate::<u8>(0, size).unwrap();
714        assert!(s >= 4096);
715        alloc.deallocate(p, s);
716    }
717}