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(
73 &self,
74 ptr: NonNull<u8>,
75 old_layout: Layout,
76 new_size: usize,
77 ) -> DomainResult<NonNull<u8>> {
78 let new_ptr = unsafe { realloc(ptr.as_ptr(), old_layout, new_size) };
80 if new_ptr.is_null() {
81 return Err(DomainError::ResourceExhausted(format!(
82 "Failed to reallocate to {} bytes",
83 new_size
84 )));
85 }
86
87 Ok(unsafe { NonNull::new_unchecked(new_ptr) })
89 }
90
91 pub unsafe fn dealloc_aligned(&self, ptr: NonNull<u8>, layout: Layout) {
99 unsafe { dealloc(ptr.as_ptr(), layout) };
101 }
102}
103
104static ALIGNED_ALLOCATOR: AlignedAllocator = AlignedAllocator::new();
105
106pub fn aligned_allocator() -> &'static AlignedAllocator {
112 &ALIGNED_ALLOCATOR
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_aligned_allocation() {
121 let allocator = AlignedAllocator::new();
122
123 unsafe {
124 for alignment in [16, 32, 64, 128, 256] {
125 let ptr = allocator.alloc_aligned(1024, alignment).unwrap();
126
127 assert_eq!(
128 ptr.as_ptr() as usize % alignment,
129 0,
130 "Pointer not aligned to {} bytes",
131 alignment
132 );
133
134 let layout = Layout::from_size_align(1024, alignment).unwrap();
135 allocator.dealloc_aligned(ptr, layout);
136 }
137 }
138 }
139
140 #[test]
141 fn test_reallocation() {
142 let allocator = AlignedAllocator::new();
143
144 unsafe {
145 let alignment = 64;
146 let initial_size = 1024;
147 let new_size = 2048;
148
149 let ptr = allocator.alloc_aligned(initial_size, alignment).unwrap();
150 let layout = Layout::from_size_align(initial_size, alignment).unwrap();
151
152 std::ptr::write_bytes(ptr.as_ptr(), 0xAB, initial_size);
153
154 let new_ptr = allocator.realloc_aligned(ptr, layout, new_size).unwrap();
155
156 assert_eq!(
157 new_ptr.as_ptr() as usize % alignment,
158 0,
159 "Reallocated pointer not aligned"
160 );
161
162 let first_byte = std::ptr::read(new_ptr.as_ptr());
163 assert_eq!(first_byte, 0xAB, "Data not preserved during reallocation");
164
165 let new_layout = Layout::from_size_align(new_size, alignment).unwrap();
166 allocator.dealloc_aligned(new_ptr, new_layout);
167 }
168 }
169
170 #[test]
171 fn test_invalid_alignment() {
172 let allocator = AlignedAllocator::new();
173 unsafe {
174 assert!(allocator.alloc_aligned(1024, 0).is_err());
175 assert!(allocator.alloc_aligned(1024, 3).is_err());
176 assert!(allocator.alloc_aligned(1024, 17).is_err());
177 }
178 }
179
180 #[test]
181 fn test_aligned_allocator_singleton() {
182 let a = aligned_allocator();
183 let b = aligned_allocator();
184 assert!(std::ptr::eq(a, b));
185 }
186}