bump_scope/alloc/
global.rs1#![expect(clippy::unused_self)]
3
4use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
5use core::{
6 alloc::Layout,
7 hint,
8 ptr::{self, NonNull},
9};
10
11use crate::polyfill;
12
13use super::{AllocError, Allocator};
14
15#[derive(Copy, Clone, Default, Debug)]
21pub struct Global;
23
24impl Global {
25 #[inline]
26 #[cfg_attr(miri, track_caller)] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
28 match layout.size() {
29 0 => Ok(NonNull::slice_from_raw_parts(polyfill::layout::dangling(layout), 0)),
30 size => unsafe {
32 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
33 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
34 Ok(NonNull::slice_from_raw_parts(ptr, size))
35 },
36 }
37 }
38
39 #[inline]
41 #[cfg_attr(miri, track_caller)] unsafe fn grow_impl(
43 &self,
44 ptr: NonNull<u8>,
45 old_layout: Layout,
46 new_layout: Layout,
47 zeroed: bool,
48 ) -> Result<NonNull<[u8]>, AllocError> {
49 debug_assert!(
50 new_layout.size() >= old_layout.size(),
51 "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
52 );
53
54 match old_layout.size() {
55 0 => self.alloc_impl(new_layout, zeroed),
56
57 old_size if old_layout.align() == new_layout.align() => unsafe {
60 let new_size = new_layout.size();
61
62 hint::assert_unchecked(new_size >= old_layout.size());
64
65 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
66 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
67 if zeroed {
68 raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
69 }
70 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
71 },
72
73 old_size => unsafe {
79 let new_ptr = self.alloc_impl(new_layout, zeroed)?;
80 ptr::copy_nonoverlapping(ptr.as_ptr(), polyfill::non_null::as_mut_ptr(new_ptr), old_size);
81 self.deallocate(ptr, old_layout);
82 Ok(new_ptr)
83 },
84 }
85 }
86}
87
88unsafe impl Allocator for Global {
89 #[inline]
90 #[cfg_attr(miri, track_caller)] fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
92 self.alloc_impl(layout, false)
93 }
94
95 #[inline]
96 #[cfg_attr(miri, track_caller)] fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
98 self.alloc_impl(layout, true)
99 }
100
101 #[inline]
102 #[cfg_attr(miri, track_caller)] unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
104 if layout.size() != 0 {
105 unsafe { dealloc(ptr.as_ptr(), layout) }
114 }
115 }
116
117 #[inline]
118 #[cfg_attr(miri, track_caller)] unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
120 unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
122 }
123
124 #[inline]
125 #[cfg_attr(miri, track_caller)] unsafe fn grow_zeroed(
127 &self,
128 ptr: NonNull<u8>,
129 old_layout: Layout,
130 new_layout: Layout,
131 ) -> Result<NonNull<[u8]>, AllocError> {
132 unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
134 }
135
136 #[inline]
137 #[cfg_attr(miri, track_caller)] unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
139 debug_assert!(
140 new_layout.size() <= old_layout.size(),
141 "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
142 );
143
144 match new_layout.size() {
145 0 => unsafe {
147 self.deallocate(ptr, old_layout);
148 Ok(NonNull::slice_from_raw_parts(polyfill::layout::dangling(new_layout), 0))
149 },
150
151 new_size if old_layout.align() == new_layout.align() => unsafe {
153 hint::assert_unchecked(new_size <= old_layout.size());
155
156 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
157 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
158 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
159 },
160
161 new_size => unsafe {
167 let new_ptr = self.allocate(new_layout)?;
168 ptr::copy_nonoverlapping(ptr.as_ptr(), polyfill::non_null::as_mut_ptr(new_ptr), new_size);
169 self.deallocate(ptr, old_layout);
170 Ok(new_ptr)
171 },
172 }
173 }
174}