1use {
2 crate::{
3 Alloc,
4 Dealloc,
5 Grow,
6 Layout,
7 Realloc,
8 Shrink,
9 error::Error,
10 helpers::{null_q_dyn, null_q_dyn_zsl_check}
11 },
12 core::{cmp::Ordering, ffi::c_void, ptr::NonNull},
13 ffi::{aligned_zalloc, c_alloc, c_dealloc, grow_aligned, shrink_aligned}
14};
15
16#[cfg_attr(miri, track_caller)]
17fn pad_then_alloc(
18 layout: Layout,
19 alloc: unsafe fn(usize, usize) -> *mut c_void
20) -> Result<NonNull<u8>, Error> {
21 null_q_dyn_zsl_check(
22 tri!(do layout.to_aligned_alloc_compatible()),
23 |l| unsafe { alloc(l.align(), l.size()) }
25 )
26}
27
28#[cfg_attr(miri, track_caller)]
29unsafe fn pad_then_grow(
30 ptr: NonNull<u8>,
31 old_layout: Layout,
32 new_layout: Layout,
33 alloc: unsafe fn(usize, usize) -> *mut c_void
34) -> Result<NonNull<u8>, Error> {
35 let old_padded = tri!(do old_layout.to_aligned_alloc_compatible());
36 let new_padded = tri!(do new_layout.to_aligned_alloc_compatible());
37
38 if old_padded.size() > new_padded.size() {
39 return Err(Error::GrowSmallerNewLayout(old_layout.size(), new_layout.size()));
40 }
41
42 null_q_dyn_zsl_check(new_padded, |l| {
43 grow_aligned(ptr.as_ptr().cast(), old_padded.size(), l.align(), l.size(), alloc)
44 })
45}
46
47#[cfg_attr(miri, track_caller)]
48unsafe fn pad_then_realloc(
49 ptr: NonNull<u8>,
50 old_layout: Layout,
51 new_layout: Layout,
52 alloc: unsafe fn(usize, usize) -> *mut c_void
53) -> Result<NonNull<u8>, Error> {
54 let old_padded = tri!(do old_layout.to_aligned_alloc_compatible());
55 let new_padded = tri!(do new_layout.to_aligned_alloc_compatible());
56
57 null_q_dyn_zsl_check(new_padded, |l| {
58 let old_ptr = ptr.as_ptr().cast();
59 let old_size = old_padded.size();
60 let old_align = old_padded.align();
61
62 let size = l.size();
63 let align = l.align();
64
65 match old_size.cmp(&new_padded.size()) {
66 Ordering::Less => unsafe { grow_aligned(old_ptr, old_size, align, size, alloc) },
69 Ordering::Equal => {
70 if align > old_align {
71 unsafe { grow_aligned(old_ptr, old_size, align, size, alloc) }
73 } else {
74 old_ptr
75 }
76 }
77 Ordering::Greater => unsafe { shrink_aligned(old_ptr, align, size) }
80 }
81 })
82}
83
84pub struct CAlloc;
90
91impl Alloc for CAlloc {
92 #[cfg_attr(miri, track_caller)]
93 #[inline]
94 fn alloc(&self, layout: Layout) -> Result<NonNull<u8>, Error> {
95 pad_then_alloc(layout, c_alloc)
96 }
97
98 #[cfg_attr(miri, track_caller)]
99 #[inline]
100 fn zalloc(&self, layout: Layout) -> Result<NonNull<u8>, Error> {
101 pad_then_alloc(layout, aligned_zalloc)
102 }
103}
104impl Dealloc for CAlloc {
105 #[cfg_attr(miri, track_caller)]
106 #[inline]
107 unsafe fn dealloc(&self, ptr: NonNull<u8>, _: Layout) {
108 c_dealloc(ptr.as_ptr().cast());
109 }
110}
111impl Grow for CAlloc {
112 #[cfg_attr(miri, track_caller)]
113 unsafe fn grow(
114 &self,
115 ptr: NonNull<u8>,
116 old_layout: Layout,
117 new_layout: Layout
118 ) -> Result<NonNull<u8>, Error> {
119 pad_then_grow(ptr, old_layout, new_layout, c_alloc)
120 }
121 #[cfg_attr(miri, track_caller)]
122 unsafe fn zgrow(
123 &self,
124 ptr: NonNull<u8>,
125 old_layout: Layout,
126 new_layout: Layout
127 ) -> Result<NonNull<u8>, Error> {
128 pad_then_grow(ptr, old_layout, new_layout, aligned_zalloc)
129 }
130}
131impl Shrink for CAlloc {
132 #[cfg_attr(miri, track_caller)]
133 unsafe fn shrink(
134 &self,
135 ptr: NonNull<u8>,
136 old_layout: Layout,
137 new_layout: Layout
138 ) -> Result<NonNull<u8>, Error> {
139 let old_padded = tri!(do old_layout.to_aligned_alloc_compatible());
140 let new_padded = tri!(do new_layout.to_aligned_alloc_compatible());
141
142 if old_padded.size() < new_padded.size() {
143 return Err(Error::ShrinkLargerNewLayout(old_layout.size(), new_layout.size()));
144 }
145
146 null_q_dyn(
147 shrink_aligned(ptr.as_ptr().cast(), new_padded.align(), new_padded.size()),
148 new_padded
149 )
150 }
151}
152impl Realloc for CAlloc {
153 #[cfg_attr(miri, track_caller)]
154 unsafe fn realloc(
155 &self,
156 ptr: NonNull<u8>,
157 old_layout: Layout,
158 new_layout: Layout
159 ) -> Result<NonNull<u8>, Error> {
160 pad_then_realloc(ptr, old_layout, new_layout, c_alloc)
161 }
162 #[cfg_attr(miri, track_caller)]
163 unsafe fn rezalloc(
164 &self,
165 ptr: NonNull<u8>,
166 old_layout: Layout,
167 new_layout: Layout
168 ) -> Result<NonNull<u8>, Error> {
169 pad_then_realloc(ptr, old_layout, new_layout, aligned_zalloc)
170 }
171}
172
173pub mod ffi;