haz_alloc_core/
alloc.rs

1use crate::__internal::UsizeExt;
2use crate::backend::Backend;
3use crate::reserve::{ReserveHeader, ReserveType, RESERVE_ALIGN};
4use crate::{huge, subhuge};
5use core::alloc::{GlobalAlloc, Layout};
6use core::marker::PhantomData;
7use core::{cmp, ptr};
8
9pub struct Alloc<B> {
10    _backend: PhantomData<B>,
11}
12
13impl<B> Copy for Alloc<B> {}
14
15impl<B> Clone for Alloc<B> {
16    #[inline]
17    fn clone(&self) -> Self {
18        Self {
19            _backend: PhantomData,
20        }
21    }
22}
23
24impl<B> Alloc<B> {
25    /// Create a new `Alloc`.
26    ///
27    /// # Safety
28    ///
29    /// All `Alloc::new` must be called with the same backend.
30    pub const unsafe fn new() -> Self {
31        Self {
32            _backend: PhantomData,
33        }
34    }
35}
36
37impl<B: Backend> Alloc<B> {
38    /// # Safety
39    ///
40    /// Layout must be valid.
41    #[inline]
42    pub unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
43        if layout.align() > RESERVE_ALIGN {
44            ptr::null_mut()
45        } else if layout.size() > subhuge::MAX || layout.align() > B::pagesize() {
46            huge::alloc::<B>(layout)
47        } else {
48            subhuge::alloc::<B>(layout, false)
49        }
50    }
51
52    /// # Safety
53    ///
54    /// Layout must be valid.
55    #[inline]
56    pub unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
57        if layout.align() > RESERVE_ALIGN {
58            ptr::null_mut()
59        } else if layout.size() > subhuge::MAX || layout.align() > B::pagesize() {
60            huge::alloc::<B>(layout)
61        } else {
62            subhuge::alloc::<B>(layout, true)
63        }
64    }
65
66    /// # Safety
67    ///
68    /// Layout and pointer must be valid.
69    ///
70    /// Alignment must match of original allocation.
71    pub unsafe fn realloc(&self, ptr: *mut u8, layout: Layout) -> *mut u8 {
72        let header = (ptr as usize - 1).align_down(RESERVE_ALIGN) as *mut ReserveHeader;
73        match (*header).ty {
74            ReserveType::Huge => {
75                if huge::realloc_in_place::<B>(header, ptr, layout) {
76                    return ptr;
77                }
78            }
79            ReserveType::SubHuge => {
80                if subhuge::realloc_in_place::<B>(header, ptr, layout) {
81                    return ptr;
82                }
83            }
84        }
85
86        let new = self.alloc(layout);
87        if new.is_null() {
88            return ptr::null_mut();
89        }
90        new.copy_from_nonoverlapping(ptr, cmp::min(layout.size(), self.size(ptr)));
91        self.dealloc(ptr);
92        new
93    }
94
95    /// # Safety
96    ///
97    /// Pointer must be valid.
98    #[inline]
99    pub unsafe fn dealloc(&self, ptr: *mut u8) {
100        let header = (ptr as usize - 1).align_down(RESERVE_ALIGN) as *mut ReserveHeader;
101        match (*header).ty {
102            ReserveType::Huge => huge::dealloc::<B>(header),
103            ReserveType::SubHuge => subhuge::dealloc::<B>(header, ptr),
104        }
105    }
106
107    /// # Safety
108    ///
109    /// Pointer must be valid.
110    #[inline]
111    pub unsafe fn size(&self, ptr: *mut u8) -> usize {
112        let header = (ptr as usize - 1).align_down(RESERVE_ALIGN) as *mut ReserveHeader;
113        match (*header).ty {
114            ReserveType::Huge => huge::size(header, ptr),
115            ReserveType::SubHuge => subhuge::size::<B>(ptr),
116        }
117    }
118}
119
120unsafe impl<B: Backend> GlobalAlloc for Alloc<B> {
121    #[inline]
122    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
123        self.alloc(layout)
124    }
125
126    #[inline]
127    unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
128        self.dealloc(ptr)
129    }
130
131    #[inline]
132    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
133        self.alloc_zeroed(layout)
134    }
135
136    #[inline]
137    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
138        self.realloc(
139            ptr,
140            Layout::from_size_align_unchecked(new_size, layout.align()),
141        )
142    }
143}