pjson_rs/parser/
aligned_alloc.rs1use crate::domain::{DomainError, DomainResult};
11use std::{
12 alloc::{Layout, alloc, dealloc, realloc},
13 ptr::NonNull,
14};
15
16#[derive(Debug, Default, Clone, Copy)]
23pub struct AlignedAllocator;
24
25impl AlignedAllocator {
26 pub const fn new() -> Self {
28 Self
29 }
30
31 pub unsafe fn alloc_aligned(&self, size: usize, alignment: usize) -> DomainResult<NonNull<u8>> {
42 if !alignment.is_power_of_two() {
43 return Err(DomainError::InvalidInput(format!(
44 "Alignment {} is not a power of 2",
45 alignment
46 )));
47 }
48
49 let layout = Layout::from_size_align(size, alignment)
50 .map_err(|e| DomainError::InvalidInput(format!("Invalid layout: {}", e)))?;
51
52 let ptr = unsafe { alloc(layout) };
54 if ptr.is_null() {
55 return Err(DomainError::ResourceExhausted(format!(
56 "Failed to allocate {} bytes with alignment {}",
57 size, alignment
58 )));
59 }
60
61 Ok(unsafe { NonNull::new_unchecked(ptr) })
63 }
64
65 pub unsafe fn realloc_aligned(
77 &self,
78 ptr: NonNull<u8>,
79 old_layout: Layout,
80 new_size: usize,
81 ) -> DomainResult<NonNull<u8>> {
82 let new_ptr = unsafe { realloc(ptr.as_ptr(), old_layout, new_size) };
84 if new_ptr.is_null() {
85 return Err(DomainError::ResourceExhausted(format!(
86 "Failed to reallocate to {} bytes",
87 new_size
88 )));
89 }
90
91 Ok(unsafe { NonNull::new_unchecked(new_ptr) })
93 }
94
95 pub unsafe fn dealloc_aligned(&self, ptr: NonNull<u8>, layout: Layout) {
103 unsafe { dealloc(ptr.as_ptr(), layout) };
105 }
106}
107
108static ALIGNED_ALLOCATOR: AlignedAllocator = AlignedAllocator::new();
109
110pub fn aligned_allocator() -> &'static AlignedAllocator {
116 &ALIGNED_ALLOCATOR
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_aligned_allocation() {
125 let allocator = AlignedAllocator::new();
126
127 unsafe {
128 for alignment in [16, 32, 64, 128, 256] {
129 let ptr = allocator.alloc_aligned(1024, alignment).unwrap();
130
131 assert_eq!(
132 ptr.as_ptr() as usize % alignment,
133 0,
134 "Pointer not aligned to {} bytes",
135 alignment
136 );
137
138 let layout = Layout::from_size_align(1024, alignment).unwrap();
139 allocator.dealloc_aligned(ptr, layout);
140 }
141 }
142 }
143
144 #[test]
145 fn test_reallocation() {
146 let allocator = AlignedAllocator::new();
147
148 unsafe {
149 let alignment = 64;
150 let initial_size = 1024;
151 let new_size = 2048;
152
153 let ptr = allocator.alloc_aligned(initial_size, alignment).unwrap();
154 let layout = Layout::from_size_align(initial_size, alignment).unwrap();
155
156 std::ptr::write_bytes(ptr.as_ptr(), 0xAB, initial_size);
157
158 let new_ptr = allocator.realloc_aligned(ptr, layout, new_size).unwrap();
159
160 assert_eq!(
161 new_ptr.as_ptr() as usize % alignment,
162 0,
163 "Reallocated pointer not aligned"
164 );
165
166 let first_byte = std::ptr::read(new_ptr.as_ptr());
167 assert_eq!(first_byte, 0xAB, "Data not preserved during reallocation");
168
169 let new_layout = Layout::from_size_align(new_size, alignment).unwrap();
170 allocator.dealloc_aligned(new_ptr, new_layout);
171 }
172 }
173
174 #[test]
175 fn test_invalid_alignment() {
176 let allocator = AlignedAllocator::new();
177 unsafe {
178 assert!(allocator.alloc_aligned(1024, 0).is_err());
179 assert!(allocator.alloc_aligned(1024, 3).is_err());
180 assert!(allocator.alloc_aligned(1024, 17).is_err());
181 }
182 }
183
184 #[test]
185 fn test_aligned_allocator_singleton() {
186 let a = aligned_allocator();
187 let b = aligned_allocator();
188 assert!(std::ptr::eq(a, b));
189 }
190}