lite_alloc/single_threaded/
freelist.rs

1use crate::PAGE_SIZE;
2use core::{
3    alloc::{GlobalAlloc, Layout},
4    ptr::{self, null_mut},
5};
6
7/// Safety Warning:
8/// Allocators in this module are designed for [Single Threaded] environments.
9/// `Sync` is implemented only to satisfy `GlobalAlloc` trait requirements.
10/// Using this allocator in a multi-threaded environment will lead to Undefined Behavior (UB).
11/// Please ensure it is used only in single-threaded environments (e.g., WASM or single-threaded embedded).
12///
13/// 安全性警示 (Safety Warning):
14/// 本模块中的分配器均为【单线程】设计。
15/// 实现了 `Sync` 仅为了满足 `GlobalAlloc` trait 的要求。
16/// 在多线程环境中使用此分配器会导致未定义行为 (UB)。
17/// 请确保只在单线程环境(如 WASM 或单线程嵌入式环境)中使用。
18unsafe impl Sync for FreeListAllocator {}
19
20/// A non-thread-safe allocator using a free list.
21/// Complexity of allocation and deallocation is O(length of free list).
22///
23/// The free list is sorted by address, and adjacent memory blocks are merged when inserting new blocks.
24///
25/// 一个使用空闲链表的非线程安全分配器。
26/// 分配和释放操作的时间复杂度为 O(空闲链表长度)。
27///
28/// 空闲链表按地址排序,并且在插入新块时会合并相邻的内存块。
29pub struct FreeListAllocator;
30
31// Global State
32static mut FREE_LIST: *mut FreeListNode = EMPTY_FREE_LIST;
33
34impl FreeListAllocator {
35    pub const fn new() -> Self {
36        FreeListAllocator
37    }
38
39    /// Testing only: Reset the internal state.
40    /// Safety: usage is inherently unsafe if allocator is in use.
41    pub unsafe fn reset() {
42        unsafe {
43            FREE_LIST = EMPTY_FREE_LIST;
44        }
45    }
46}
47
48const EMPTY_FREE_LIST: *mut FreeListNode = usize::MAX as *mut FreeListNode;
49
50/// Stored at the beginning of each free segment.
51/// Note: This could be packed into 1 word (using low bits to mark this case,
52/// and only using the second word when allocation size is larger than 1 word).
53///
54/// 存储在每个空闲段的开头。
55/// 注意:可以将其放入 1 个字中(使用低位标记该情况,
56/// 然后仅在分配大小大于 1 个字时使用第二个字)
57struct FreeListNode {
58    next: *mut FreeListNode,
59    size: usize,
60}
61
62const NODE_SIZE: usize = core::mem::size_of::<FreeListNode>();
63
64// Safety: No one else owns the raw pointer (conceptually), logic is same.
65unsafe impl Send for FreeListAllocator {}
66
67unsafe impl GlobalAlloc for FreeListAllocator {
68    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
69        // 1. Force fixed alignment to 16 bytes (covering u8 to u128/v128)
70        // This saves you from complex dynamic alignment logic reading layout.align()
71        // 1. 强制固定对齐为 16 字节 (覆盖 u8 到 u128/v128)
72        // 这样你就不用读取 layout.align() 来做复杂的动态对齐逻辑了
73        const MIN_ALIGN: usize = 16;
74
75        // 2. If user requests more aggressive alignment (e.g. 4KB page alignment), must handle or fail
76        // For size, you can choose not to support alignment > 16 (return null or panic)
77        // 2. 如果用户请求了更变态的对齐 (比如 4KB 对齐的页),必须处理或失败
78        // 为了体积,你可以选择直接不支持超过 16 的对齐(直接返回 null 或 panic)
79        if layout.align() > MIN_ALIGN {
80            return null_mut();
81        }
82
83        // 3. Calculate size: round up to multiple of 16
84        // Assume NODE_SIZE is also 16 bytes or smaller
85        // 3. 计算大小:向上取整到 16 的倍数
86        // 假设 NODE_SIZE 也是 16 字节或更小
87        let size = layout.size().max(NODE_SIZE);
88        // Fast bitwise round up to 16
89        // 快速位运算取整 (等同于 round_up to 16)
90        let size = (size + 15) & !15;
91
92        let mut free_list: *mut *mut FreeListNode = ptr::addr_of_mut!(FREE_LIST);
93        // Search the free list
94        // 搜索空闲链表
95        loop {
96            // SAFETY: Dereferencing free_list is safe
97            // SAFETY: 解引用 free_list 是安全的
98            if unsafe { *free_list == EMPTY_FREE_LIST } {
99                break;
100            }
101
102            let node = unsafe { *free_list };
103            let node_size = unsafe { (*node).size };
104
105            if size <= node_size {
106                let remaining = node_size - size;
107                // If remaining space is large enough, keep it in the list
108                // 如果剩余空间足够大,我们将其保留在链表中
109                if remaining >= NODE_SIZE {
110                    unsafe {
111                        (*node).size = remaining;
112                        return (node as *mut u8).add(remaining);
113                    }
114                } else {
115                    // Otherwise, allocate the whole block
116                    // 否则,整个块都分配出去
117                    unsafe {
118                        *free_list = (*node).next;
119                        return node as *mut u8;
120                    }
121                }
122            }
123            // SAFETY: Move to next node.
124            // SAFETY: 移动到下一个节点。
125            unsafe {
126                free_list = ptr::addr_of_mut!((*node).next);
127            }
128        }
129
130        // No space found in free list.
131        // 未在空闲链表中找到空间。
132        let requested_bytes = round_up(size, PAGE_SIZE);
133        // SAFETY: Call global grow_memory (shimmed on non-wasm)
134        let previous_page_count = unsafe { crate::grow_memory(requested_bytes / PAGE_SIZE) };
135        if previous_page_count == usize::MAX {
136            return null_mut();
137        }
138
139        let ptr = (previous_page_count * PAGE_SIZE) as *mut u8;
140        // SAFETY: Recursive call to self to add new memory block.
141        // SAFETY: 递归调用自身,添加新的内存块。
142        unsafe {
143            self.dealloc(
144                ptr,
145                Layout::from_size_align_unchecked(requested_bytes, PAGE_SIZE),
146            );
147            self.alloc(layout)
148        }
149    }
150
151    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
152        debug_assert!(ptr.align_offset(NODE_SIZE) == 0);
153        let ptr = ptr as *mut FreeListNode;
154        let size = full_size(layout);
155        // SAFETY: Pointer arithmetic
156        // SAFETY: 指针算术
157        // Used to merge with the next node if adjacent.
158        // 用于在相邻时与下一个节点合并。
159        let after_new = unsafe { offset_bytes(ptr, size) };
160
161        // SAFETY: Get static mutable pointer
162        // SAFETY: 获取静态可变指针
163        let mut free_list: *mut *mut FreeListNode = ptr::addr_of_mut!(FREE_LIST);
164        // Insert into free list, sorted by pointer descending.
165        // 插入到空闲链表中,该链表按指针降序存储。
166        loop {
167            // SAFETY: Dereference free_list to check if empty or compare address
168            // SAFETY: 解引用 free_list 检查是否为空或比较地址
169            if unsafe { *free_list == EMPTY_FREE_LIST } {
170                // SAFETY: Write new node and insert at head
171                // SAFETY: 写入新节点并插入链表头
172                unsafe {
173                    (*ptr).next = EMPTY_FREE_LIST;
174                    (*ptr).size = size;
175                    *free_list = ptr;
176                }
177                return;
178            }
179
180            // SAFETY: *free_list is a valid node pointer because we checked EMPTY_FREE_LIST above
181            // SAFETY: *free_list 是一个有效的节点指针,因为我们上面检查了 EMPTY_FREE_LIST
182            if unsafe { *free_list == after_new } {
183                // Merge new node into the node after it.
184                // 将新节点合并到此节点之后的节点中。
185
186                // SAFETY: Access fields
187                // SAFETY: 访问字段
188                let new_size = unsafe { size + (**free_list).size };
189                let next = unsafe { (**free_list).next };
190
191                // SAFETY: Check next continuity
192                // SAFETY: 检查 next 连续性
193                if unsafe { next != EMPTY_FREE_LIST && offset_bytes(next, (*next).size) == ptr } {
194                    // Merge into the node before this node, and the one after.
195                    // 合并到此节点之前的节点,以及之后的节点。
196                    // SAFETY: Update next size, remove current node
197                    // SAFETY: 更新 next 的大小,移除当前节点
198                    unsafe {
199                        (*next).size += new_size;
200                        *free_list = next;
201                    }
202                    return;
203                }
204                // Edit node in free list, move its position and update its size.
205                // 编辑空闲链表中的节点,移动其位置并更新其大小。
206                // SAFETY: Pointer operations
207                // SAFETY: 指针操作
208                unsafe {
209                    *free_list = ptr;
210                    (*ptr).size = new_size;
211                    (*ptr).next = next;
212                }
213                return;
214            }
215
216            if unsafe { *free_list < ptr } {
217                // If adjacent, merge to the end of current node
218                // 如果相邻,则合并到当前节点的末尾
219                // SAFETY: ptr comparison and offset_bytes are pointer arithmetic
220                // SAFETY: 这里的 ptr 比较和 offset_bytes 都是指针算术
221                if unsafe { offset_bytes(*free_list, (**free_list).size) == ptr } {
222                    // Merge into the node before this node (and potentially after).
223                    // 合并到此节点之前的节点,以及之后的节点。
224                    // SAFETY: Only need to update size
225                    // SAFETY: 只需更新大小
226                    unsafe {
227                        (**free_list).size += size;
228                    }
229                    // Since we merged new node to the end of existing node, no need to update pointers, just change size.
230                    // 因为我们将新节点合并到现有节点的末尾,所以不需要更新指针,只需更改大小。
231                    return;
232                }
233                // Create a new free list node
234                // 创建一个新的空闲链表节点
235                // SAFETY: List insertion
236                // SAFETY: 链表插入
237                unsafe {
238                    (*ptr).next = *free_list;
239                    (*ptr).size = size;
240                    *free_list = ptr;
241                }
242                return;
243            }
244            // SAFETY: Move pointer
245            // SAFETY: 移动指针
246            unsafe {
247                free_list = ptr::addr_of_mut!((**free_list).next);
248            }
249        }
250    }
251    #[cfg(feature = "realloc")]
252    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
253        // 1. Calculate original block size (consistent with alloc/dealloc)
254        // 1. 计算原块大小 (与 alloc/dealloc 一致)
255        let old_size = full_size(layout);
256        // 2. Calculate new block size (aligned)
257        // 2. 计算新块大小 (对齐)
258        let new_full_size = (new_size.max(NODE_SIZE) + 15) & !15;
259
260        // case A: Shrinking
261        if new_full_size <= old_size {
262            let diff = old_size - new_full_size;
263            // If remaining space is large enough, split and free the remainder
264            // 如果剩余空间足够大,切分并释放剩余部分
265            if diff >= NODE_SIZE {
266                unsafe {
267                    let remainder = ptr.add(new_full_size);
268                    // Construct a Layout for freeing
269                    // align=16 is safe because all our blocks are 16-aligned
270                    // 构造一个 Layout 用于释放
271                    // align=16 是安全的,因为我们所有的块都是 16 对齐
272                    let remainder_layout = Layout::from_size_align_unchecked(diff, 16);
273                    self.dealloc(remainder, remainder_layout);
274                }
275            }
276            return ptr;
277        }
278
279        // case B: Growing
280        // Try to merge backwards (In-place grow)
281        // Our list is [Sorted Descending by Address]
282        // 尝试向后合并 (In-place grow)
283        // 我们的链表是【地址降序】 (Descending)
284        // Check if `ptr + old_size` is a free node.
285        let needed = new_full_size - old_size;
286        let target_addr = unsafe { ptr.add(old_size) as *mut FreeListNode };
287
288        let mut prev = ptr::addr_of_mut!(FREE_LIST);
289        loop {
290            let curr = unsafe { *prev };
291            if curr == EMPTY_FREE_LIST {
292                break;
293            }
294
295            // List Descending: 2000 -> 1000 -> 500
296            // If curr (2000) > target (1500), continue searching
297            // If curr (1500) == target (1500), found it
298            // If curr (1000) < target (1500), means target is not in list (missed)
299            // 链表降序: 2000 -> 1000 -> 500
300            // 如果 curr (2000) > target (1500),继续找
301            // 如果 curr (1500) == target (1500),找到
302            // 如果 curr (1000) < target (1500),说明 target 不在链表中 (已错过)
303
304            if curr < target_addr {
305                // Missed
306                break;
307            }
308
309            if curr == target_addr {
310                // Found adjacent free block
311                // Check size
312                let node_size = unsafe { (*curr).size };
313                if node_size >= needed {
314                    // Merge!
315                    // 1. Remove 'curr' from free list
316                    unsafe {
317                        *prev = (*curr).next;
318                    }
319
320                    // 2. If 'curr' had extra space, put the remainder back
321                    let remaining_in_node = node_size - needed;
322                    if remaining_in_node >= NODE_SIZE {
323                        unsafe {
324                            // Create remainder node
325                            let remainder_addr = (curr as *mut u8).add(needed) as *mut FreeListNode;
326                            (*remainder_addr).size = remaining_in_node;
327
328                            // Insert remainder back into list.
329                            // Since remainder_addr > curr (sub-part of curr, higher address).
330                            // And *prev points to Next (which is < curr).
331                            // So Remainder > Next.
332                            // Remainder should replace Curr's position.
333                            (*remainder_addr).next = (*curr).next;
334                            *prev = remainder_addr;
335                        }
336                    }
337                    return ptr;
338                }
339                // Adjacent block exists but too small.
340                break;
341            }
342
343            // Next
344            unsafe {
345                prev = ptr::addr_of_mut!((*curr).next);
346            }
347        }
348
349        // Default Fallback: Alloc new, Copy, Dealloc old
350        // 默认回退: Alloc new, Copy, Dealloc old
351        unsafe {
352            let new_ptr = self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()));
353            if !new_ptr.is_null() {
354                ptr::copy_nonoverlapping(ptr, new_ptr, layout.size());
355                self.dealloc(ptr, layout);
356            }
357            new_ptr
358        }
359    }
360}
361
362fn full_size(layout: Layout) -> usize {
363    let grown = layout.size().max(NODE_SIZE);
364    (grown + 15) & !15
365}
366
367/// Round up value to the nearest multiple of increment, where increment must be a power of 2.
368/// If `value` is already a multiple of increment, it remains unchanged.
369///
370/// 将值向上取整到增量的最接近倍数,增量必须是 2 的幂。
371/// 如果 `value` 是增量的倍数,则保持不变。
372fn round_up(value: usize, increment: usize) -> usize {
373    debug_assert!(increment.is_power_of_two());
374    // Calculate `value.div_ceil(increment) * increment`,
375    // utilizing the fact that `increment` is always a power of 2 to avoid integer division,
376    // as it is not always optimized away.
377    // 计算 `value.div_ceil(increment) * increment`,
378    // 利用 `increment` 总是 2 的幂这一事实避免使用整数除法,
379    // 因为它并不总是会被优化掉。
380    multiple_below(value + (increment - 1), increment)
381}
382
383/// Round down value to the nearest multiple of increment, where increment must be a power of 2.
384/// If `value` is a multiple of `increment`, it remains unchanged.
385///
386/// 将值向下取整到增量的最接近倍数,增量必须是 2 的幂。
387/// 如果 `value` 是 `increment` 的倍数,则保持不变。
388fn multiple_below(value: usize, increment: usize) -> usize {
389    debug_assert!(increment.is_power_of_two());
390    // Calculate `value / increment * increment`,
391    // utilizing the fact that `increment` is always a power of 2 to avoid integer division,
392    // as it is not always optimized away.
393    // 计算 `value / increment * increment`,
394    // 利用 `increment` 总是 2 的幂这一事实避免使用整数除法,
395    // 因为它并不总是会被优化掉。
396    value & increment.wrapping_neg()
397}
398
399unsafe fn offset_bytes(ptr: *mut FreeListNode, offset: usize) -> *mut FreeListNode {
400    unsafe { (ptr as *mut u8).add(offset) as *mut FreeListNode }
401}
402
403#[cfg(test)]
404mod tests {
405    use super::*;
406    use crate::reset_heap;
407    use std::sync::{Mutex, MutexGuard};
408
409    static TEST_MUTEX: Mutex<()> = Mutex::new(());
410
411    struct SafeAllocator {
412        inner: FreeListAllocator,
413        _guard: MutexGuard<'static, ()>,
414    }
415
416    impl SafeAllocator {
417        fn new() -> Self {
418            let guard = TEST_MUTEX.lock().unwrap();
419            unsafe {
420                FreeListAllocator::reset();
421                reset_heap();
422                Self {
423                    inner: FreeListAllocator::new(),
424                    _guard: guard,
425                }
426            }
427        }
428
429        fn alloc(&self, layout: Layout) -> *mut u8 {
430            unsafe { self.inner.alloc(layout) }
431        }
432
433        fn dealloc(&self, ptr: *mut u8, layout: Layout) {
434            unsafe { self.inner.dealloc(ptr, layout) }
435        }
436    }
437
438    impl Drop for SafeAllocator {
439        fn drop(&mut self) {
440            unsafe {
441                FreeListAllocator::reset();
442                reset_heap();
443            }
444        }
445    }
446
447    #[test]
448    fn test_basic_allocation() {
449        let allocator = SafeAllocator::new();
450        let layout = Layout::new::<u64>();
451        let ptr = allocator.alloc(layout);
452        assert!(!ptr.is_null());
453
454        unsafe {
455            *ptr.cast::<u64>() = 0xDEADBEEF;
456            assert_eq!(*ptr.cast::<u64>(), 0xDEADBEEF);
457        }
458
459        allocator.dealloc(ptr, layout);
460    }
461
462    #[test]
463    fn test_allocation_order_descending() {
464        let allocator = SafeAllocator::new();
465        let layout = Layout::from_size_align(16, 16).unwrap();
466
467        // 第一次分配,会触发 gro_memory (64KB),并全部加到 FreeList (Head -> Node(size=64KB))
468        // alloc 会找到这个大块,由于 size 小,它会在 high address 切个块出来给你?
469        // 让我们看看 alloc 逻辑:
470        // if remaining >= NODE_SIZE { (*node).size = remaining; return node + remaining; }
471        // 意味着,它保留了 block 的低地址部分作为新的 FreeNode,返回了高地址部分给用户。
472        // 所以第一个分配的地址应该是 PageEnd - 16。
473        let ptr1 = allocator.alloc(layout);
474
475        // 第二次分配,应当再次从那个剩余的 FreeNode (位于低地址) 的末尾切一块。
476        // 所以 ptr2 应该在 ptr1 之前。
477        let ptr2 = allocator.alloc(layout);
478
479        assert!(!ptr1.is_null());
480        assert!(!ptr2.is_null());
481
482        // 指针地址应该递减:ptr1 > ptr2
483        assert!(ptr1 > ptr2);
484
485        // 它们应该是紧挨著的:Block: [... | ptr2 | ptr1 | end]
486        assert_eq!(ptr1 as usize - ptr2 as usize, 16);
487    }
488
489    #[test]
490    fn test_reuse() {
491        let allocator = SafeAllocator::new();
492        let layout = Layout::from_size_align(16, 16).unwrap();
493
494        let ptr1 = allocator.alloc(layout);
495        allocator.dealloc(ptr1, layout);
496
497        // 释放后,ptr1 对应的块被放回 FreeList。
498        // 因为它是刚刚分配出的最高地址块,且我们没有其他操作,它应该会被合并回大块,或者作为独立块。
499        // 再次分配时,应该优先使用最高地址的块 (Search order)。
500        // 如果合并回去,它就成了大块的一部分(高位),下次 alloc 切割时,会切同样的地址。
501        // 如果没合并(中间有断开),它可能是独立的 Node。 Search 顺序是 Descending。
502        // 大块在低地址,ptr1 在高地址。 Search 先遇到 ptr1 还是 大块?
503        // FreeList 是 Descending。所以先遇到 ptr1。
504        // 如果 ptr1 能满足大小,就用 ptr1。
505        let ptr2 = allocator.alloc(layout);
506        assert_eq!(ptr1, ptr2);
507    }
508
509    #[test]
510    fn test_coalescing_merge() {
511        let allocator = SafeAllocator::new();
512        let layout = Layout::from_size_align(128, 16).unwrap();
513
514        // 分配 3 个块。顺序:ptr1 (high) > ptr2 > ptr3 (low)
515        let ptr1 = allocator.alloc(layout);
516        let ptr2 = allocator.alloc(layout);
517        let ptr3 = allocator.alloc(layout);
518
519        assert_eq!(ptr1 as usize - ptr2 as usize, 128);
520        assert_eq!(ptr2 as usize - ptr3 as usize, 128);
521
522        // 释放中间的 (ptr2)。
523        // 此时 FreeList: [...BigBlock..., ptr2] (如果没和其他合并)
524        allocator.dealloc(ptr2, layout);
525
526        // 释放顶部的 (ptr1)。
527        // ptr1 > ptr2. ptr1 是高地址。
528        // dealloc 插入 ptr1。它发现 ptr1 > ptr2 (Head).
529        // 且 ptr2 + 128 == ptr1。应该导致 ptr2 (Node) 扩展大小,吞并 ptr1。
530        // 结果: FreeList 中有一个合并后的块 [ptr2, ptr1] (Size 256).
531        allocator.dealloc(ptr1, layout);
532
533        // 释放底部的 (ptr3)。
534        // ptr3 < ptr2.
535        // 插入 ptr3。找到 Head (ptr2_ptr1_merged).
536        // 检查: ptr3 + 128 == ptr2 ? Yes.
537        // 合并:ptr3 变成新的 Head,Size += 256. -> [ptr3, ptr2, ptr1] (Size 384).
538        allocator.dealloc(ptr3, layout);
539
540        // 现在申请一个 384 字节的大块。
541        // 它应该完美匹配我们刚刚合并出的那个块 (位于 ptr3)。
542        let layout_large = Layout::from_size_align(384, 16).unwrap();
543        let ptr_large = allocator.alloc(layout_large);
544
545        assert!(!ptr_large.is_null());
546        // 如果 alloc 逻辑是 "如果正好大小相等,就移除节点并返回整个节点指针",
547        // 那么应该返 ptr3。
548        // 如果 alloc 逻辑是 "如果剩余 >= NODE_SIZE 才分割",这里剩余 0,所以不分割。
549        // 直接返回节点地址。
550        assert_eq!(ptr_large, ptr3);
551    }
552
553    #[test]
554    fn test_memory_growth_multi_page() {
555        let allocator = SafeAllocator::new();
556        // 分配 40KB。
557        let layout = Layout::from_size_align(40 * 1024, 16).unwrap();
558        let ptr1 = allocator.alloc(layout);
559        assert!(!ptr1.is_null());
560
561        // 再分配 40KB。当前页 (64KB) 剩 24KB,不够。
562        // 触发 grow_memory。
563        // 分配器会申请新页。返回新页的高地址部分。
564        let ptr2 = allocator.alloc(layout);
565        assert!(!ptr2.is_null());
566        assert_ne!(ptr1, ptr2);
567
568        // 两个指针应该相距较远 (至少 40KB)
569        let dist = if ptr1 > ptr2 {
570            ptr1 as usize - ptr2 as usize
571        } else {
572            ptr2 as usize - ptr1 as usize
573        };
574        assert!(dist >= 40 * 1024);
575    }
576
577    #[test]
578    fn test_alignment_large() {
579        let allocator = SafeAllocator::new();
580        // 目前实现只支持 max align 16。
581        // 如果请求 32,应该返回 null。 (代码里写了 check)
582        let layout_bad = Layout::from_size_align(32, 32).unwrap();
583        let ptr = allocator.alloc(layout_bad);
584        assert!(ptr.is_null());
585    }
586
587    #[test]
588    fn test_fragmentation_fill_hole() {
589        let allocator = SafeAllocator::new();
590        let layout = Layout::from_size_align(64, 16).unwrap();
591
592        // Pointers decrease: p1 > p2 > p3
593        let _p1 = allocator.alloc(layout);
594        let p2 = allocator.alloc(layout);
595        let p3 = allocator.alloc(layout);
596
597        // Free p2. 制造一个 64B 的空洞。
598        allocator.dealloc(p2, layout);
599
600        // 再分配 64B。
601        // Allocator 策略是遍历 FreeList (Descending)。
602        // 列表里有: [Head (Rest of Memory at Low Address), p2 (at Higher Address)]
603        // p2 > Head. 所以 p2 排在前面。
604        // alloc 查 p2,大小正好。
605        // 应该重用 p2。
606
607        let p4 = allocator.alloc(layout);
608        assert_eq!(p4, p2);
609
610        // 确保 p3 还没被分配出去
611        let _p5 = allocator.alloc(layout);
612        // p5 应该是从 Head (Low Address) 切出来的,应该小于 p3
613        assert!(_p5 < p3);
614    }
615    #[test]
616    fn test_realloc_shrink_in_place() {
617        let allocator = SafeAllocator::new();
618        let layout = Layout::from_size_align(128, 16).unwrap();
619        let ptr = allocator.alloc(layout);
620        assert!(!ptr.is_null());
621
622        unsafe {
623            ptr.write_bytes(0xAA, layout.size());
624        }
625
626        // Shrink to 64
627        let new_size = 64;
628        let new_layout = Layout::from_size_align(new_size, 16).unwrap();
629
630        // We need to call realloc from GlobalAlloc trait
631        let realloc_ptr = unsafe { allocator.inner.realloc(ptr, layout, new_size) };
632
633        // Custom impl is In-Place.
634        #[cfg(feature = "realloc")]
635        assert_eq!(ptr, realloc_ptr);
636
637        #[cfg(not(feature = "realloc"))]
638        assert_ne!(ptr, realloc_ptr);
639
640        unsafe {
641            assert_eq!(*realloc_ptr.cast::<u8>(), 0xAA);
642        }
643
644        allocator.dealloc(realloc_ptr, new_layout);
645    }
646
647    #[test]
648    fn test_realloc_grow_in_place() {
649        let allocator = SafeAllocator::new();
650        let layout = Layout::from_size_align(64, 16).unwrap();
651
652        let ptr1 = allocator.alloc(layout);
653        let ptr2 = allocator.alloc(layout);
654
655        assert_eq!(ptr1 as usize - ptr2 as usize, 64);
656
657        allocator.dealloc(ptr1, layout);
658
659        let new_size = 128;
660        let ptr2_new = unsafe { allocator.inner.realloc(ptr2, layout, new_size) };
661
662        #[cfg(feature = "realloc")]
663        assert_eq!(ptr2, ptr2_new);
664
665        #[cfg(not(feature = "realloc"))]
666        assert_ne!(ptr2, ptr2_new);
667
668        allocator.dealloc(ptr2_new, Layout::from_size_align(new_size, 16).unwrap());
669    }
670}