commonlibsse_ng\re\b\BSTHashMap/
allocator.rs

1use core::alloc::Layout;
2use core::{marker::PhantomData, ptr::NonNull};
3use core::{mem, ptr};
4
5use crate::re::MemoryManager::alloc::{alloc_zeroed, dealloc};
6
7use generic_array::{ArrayLength, GenericArray};
8use stdx::alloc::{AllocError, non_null_empty_slice};
9use typenum::{U2, op};
10
11/// A trait representing a generic memory allocator.
12/// Provides methods for allocating and deallocating raw bytes.
13pub trait Allocator {
14    /// Allocates a block of memory of the specified size in bytes and initializes it to zero.
15    ///
16    /// # Safety
17    /// See [`std::alloc::GlobalAlloc::alloc`].
18    ///
19    /// # Errors
20    /// Returns `AllocError` if the allocation fails.
21    unsafe fn allocate_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
22
23    /// Deallocates a previously allocated block of memory.
24    ///
25    /// # Safety
26    /// This function is unsafe if called with an invalid or null pointer.
27    unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout);
28
29    /// Returns the minimum size that can be allocated by this allocator.
30    ///
31    /// Must be `> 0`.
32    #[inline]
33    fn min_size() -> u32 {
34        1 << 3
35    }
36
37    /// Gets the current entries pointer.
38    fn get_entries(&self) -> *mut u8;
39
40    /// Sets the entries pointer.
41    fn set_entries(&mut self, entries: *mut u8);
42}
43
44/// An allocator implementation for the BSTScatterTable.
45///
46/// This allocator uses the Rust standard library's `alloc` and `dealloc` functions
47/// to manage dynamic memory allocation, similar to C++'s `malloc` and `free`.
48#[repr(C)]
49#[derive(Debug)]
50pub struct BSTScatterTableHeapAllocator {
51    /// 64-bit padding to match the original memory layout.
52    pad00: u64,
53
54    /// Pointer to the allocated memory block.
55    entries: *mut u8,
56}
57
58impl Default for BSTScatterTableHeapAllocator {
59    #[inline]
60    fn default() -> Self {
61        Self::new()
62    }
63}
64
65impl BSTScatterTableHeapAllocator {
66    /// Creates a new `BSTScatterTableHeapAllocator` instance with null entries.
67    #[inline]
68    pub const fn new() -> Self {
69        Self { pad00: 0, entries: ptr::null_mut() }
70    }
71}
72
73impl Allocator for BSTScatterTableHeapAllocator {
74    /// Allocates a block of memory of the specified size in bytes.
75    ///
76    /// # Panics
77    /// Panics under the following conditions.
78    /// - If `bytes_size` is not a multiple of usize.
79    unsafe fn allocate_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
80        debug_assert!(layout.size() % mem::size_of::<usize>() == 0, "Bytes must be aligned");
81
82        let ptr = unsafe { alloc_zeroed(layout) };
83        if ptr.is_null() {
84            return Err(AllocError);
85        }
86
87        self.entries = ptr;
88        Ok(match layout.size() {
89            0 => non_null_empty_slice(layout),
90            size => NonNull::slice_from_raw_parts(unsafe { NonNull::new_unchecked(ptr) }, size),
91        })
92    }
93
94    unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) {
95        unsafe { dealloc(ptr.as_ptr(), layout) }
96    }
97
98    #[inline]
99    fn get_entries(&self) -> *mut u8 {
100        self.entries
101    }
102
103    #[inline]
104    fn set_entries(&mut self, entries: *mut u8) {
105        self.entries = entries;
106    }
107}
108
109/// `BSTStaticHashMapBase::Allocator` equivalent in Rust using `GenericArray`
110#[repr(C)]
111#[derive(Debug)]
112pub struct BSTStaticHashMapBaseAllocator<N, A>
113where
114    N: ArrayLength,
115    U2: core::ops::Mul<N>,
116    A: ArrayLength,
117    op!(U2 * N): ArrayLength,
118{
119    buffer: GenericArray<u8, N>, // Stack buffer
120    entries: *mut u8,            // Pointer to entries
121    _align: PhantomData<A>,      // Alignment marker
122}
123
124impl<N, A> Default for BSTStaticHashMapBaseAllocator<N, A>
125where
126    N: ArrayLength,
127    U2: core::ops::Mul<N>,
128    A: ArrayLength,
129    op!(U2 * N): ArrayLength,
130{
131    #[inline]
132    fn default() -> Self {
133        Self::new()
134    }
135}
136
137impl<N, A> BSTStaticHashMapBaseAllocator<N, A>
138where
139    N: ArrayLength,
140    U2: core::ops::Mul<N>,
141    A: ArrayLength,
142    op!(U2 * N): ArrayLength,
143{
144    /// Creates a new allocator instance
145    pub fn new() -> Self {
146        const {
147            assert!(N::USIZE > 0 && N::USIZE.is_power_of_two(), "N must be a power of two");
148        };
149
150        Self { buffer: GenericArray::default(), entries: ptr::null_mut(), _align: PhantomData }
151    }
152}
153
154impl<N, A> Allocator for BSTStaticHashMapBaseAllocator<N, A>
155where
156    N: ArrayLength,
157    A: ArrayLength,
158    U2: core::ops::Mul<N>,
159    op!(U2 * N): ArrayLength,
160{
161    /// Returns the minimum size
162    #[inline]
163    fn min_size() -> u32 {
164        N::U32
165    }
166
167    /// Allocates memory
168    ///
169    /// # Panics
170    /// Panics if the size is not a multiple of `N::USIZE`.
171    #[inline]
172    unsafe fn allocate_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
173        let size = layout.size();
174        assert!(size % N::USIZE == 0, "Bytes must be aligned to S");
175
176        let len = self.buffer.len();
177        let Some(ptr) = NonNull::new(self.buffer.as_mut_ptr()) else {
178            return Err(AllocError);
179        };
180        if size <= len {
181            return Ok(match size {
182                0 => non_null_empty_slice(layout),
183                size => NonNull::slice_from_raw_parts(ptr, size),
184            });
185        }
186
187        Err(AllocError)
188    }
189
190    /// No-op deallocation
191    #[inline]
192    unsafe fn deallocate(&mut self, ptr: NonNull<u8>, _: Layout) {
193        assert!(ptr.as_ptr() == self.buffer.as_mut_ptr(), "Invalid pointer");
194    }
195
196    #[inline]
197    fn get_entries(&self) -> *mut u8 {
198        self.entries
199    }
200
201    #[inline]
202    fn set_entries(&mut self, entries: *mut u8) {
203        assert!(entries == self.buffer.as_mut_ptr() || entries.is_null());
204        self.entries = entries;
205    }
206}