std_fork\alloc/
impl_global.rs1use super::SelflessAllocator;
7use core::ptr;
8use core::{alloc::Layout, hint, ptr::NonNull};
9use std::alloc::{alloc, alloc_zeroed, dealloc, realloc};
10use stdx::alloc::{AllocError, Global, non_null_empty_slice};
11
12#[inline]
13#[cfg_attr(miri, track_caller)] #[allow(clippy::unused_self)]
15pub(crate) fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
16 match layout.size() {
17 0 => Ok(non_null_empty_slice(layout)),
18 size => unsafe {
20 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
21 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
22 Ok(NonNull::slice_from_raw_parts(ptr, size))
23 },
24 }
25}
26
27#[inline]
29#[cfg_attr(miri, track_caller)] pub(crate) unsafe fn grow_impl(
31 ptr: NonNull<u8>,
32 old_layout: Layout,
33 new_layout: Layout,
34 zeroed: bool,
35) -> Result<NonNull<[u8]>, AllocError> {
36 debug_assert!(
37 new_layout.size() >= old_layout.size(),
38 "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
39 );
40
41 match old_layout.size() {
42 0 => alloc_impl(new_layout, zeroed),
43
44 old_size if old_layout.align() == new_layout.align() => unsafe {
47 let new_size = new_layout.size();
48
49 hint::assert_unchecked(new_size >= old_layout.size());
51
52 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
53 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
54 if zeroed {
55 raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
56 }
57 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
58 },
59
60 old_size => unsafe {
66 let new_ptr = alloc_impl(new_layout, zeroed)?;
67 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.cast().as_ptr(), old_size);
68 deallocate(ptr, old_layout);
69 Ok(new_ptr)
70 },
71 }
72}
73
74#[inline]
75#[cfg_attr(miri, track_caller)] unsafe fn deallocate(ptr: NonNull<u8>, layout: Layout) {
77 if layout.size() != 0 {
78 unsafe { dealloc(ptr.as_ptr(), layout) }
81 }
82}
83
84unsafe impl SelflessAllocator for Global {
85 #[inline]
86 #[cfg_attr(miri, track_caller)] fn allocate(layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
88 alloc_impl(layout, false)
89 }
90
91 #[inline]
92 #[cfg_attr(miri, track_caller)] fn allocate_zeroed(layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
94 alloc_impl(layout, true)
95 }
96
97 #[inline]
98 #[cfg_attr(miri, track_caller)] unsafe fn deallocate(ptr: NonNull<u8>, layout: Layout) {
100 if layout.size() != 0 {
101 unsafe { dealloc(ptr.as_ptr(), layout) }
104 }
105 }
106
107 #[inline]
108 #[cfg_attr(miri, track_caller)] unsafe fn grow(
110 ptr: NonNull<u8>,
111 old_layout: Layout,
112 new_layout: Layout,
113 ) -> Result<NonNull<[u8]>, AllocError> {
114 unsafe { grow_impl(ptr, old_layout, new_layout, false) }
116 }
117
118 #[inline]
119 #[cfg_attr(miri, track_caller)] unsafe fn grow_zeroed(
121 ptr: NonNull<u8>,
122 old_layout: Layout,
123 new_layout: Layout,
124 ) -> Result<NonNull<[u8]>, AllocError> {
125 unsafe { grow_impl(ptr, old_layout, new_layout, true) }
127 }
128
129 #[inline]
130 #[cfg_attr(miri, track_caller)] unsafe fn shrink(
132 ptr: NonNull<u8>,
133 old_layout: Layout,
134 new_layout: Layout,
135 ) -> Result<NonNull<[u8]>, AllocError> {
136 debug_assert!(
137 new_layout.size() <= old_layout.size(),
138 "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
139 );
140
141 match new_layout.size() {
142 0 => {
144 unsafe { Self::deallocate(ptr, old_layout) };
145 Ok(non_null_empty_slice(new_layout))
146 }
147
148 new_size if old_layout.align() == new_layout.align() => unsafe {
150 hint::assert_unchecked(new_size <= old_layout.size());
152
153 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
154 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
155 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
156 },
157
158 new_size => unsafe {
164 let new_ptr = Self::allocate(new_layout)?;
165 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.cast().as_ptr(), new_size);
166 Self::deallocate(ptr, old_layout);
167 Ok(new_ptr)
168 },
169 }
170 }
171}