1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! UNUSED - OPEN AN ISSUE IF YOU'D FIND THIS USEFUL
use core::ops::DerefMut;
use crate::{Binning, base::Talc, source::Source};
pub trait AsTalc<S: Source, B: Binning> {
fn as_talc(&self) -> impl DerefMut<Target = Talc<S, B>>;
}
macro_rules! impl_global_alloc {
($talc:ty) => {
unsafe impl<S: ::crate::Source, B: ::crate::Binning> core::alloc::GlobalAlloc for $talc {
#[inline]
#[track_caller]
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
talc.as_talc().allocate(layout).unwrap_or(core::ptr::null_mut(), |nn| nn.as_ptr())
}
#[inline]
#[track_caller]
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
talc.as_talc().deallocate(ptr, layout);
}
#[inline]
#[track_caller]
unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 {
let size = layout.size();
// SAFETY: the safety contract for `alloc` must be upheld by the caller.
let ptr = unsafe { self.alloc(layout) };
if !ptr.is_null() {
// SAFETY: as allocation succeeded, the region from `ptr`
// of size `size` is guaranteed to be valid for writes.
unsafe { core::ptr::write_bytes(ptr, 0, size) };
}
ptr
}
#[cfg(not(any(
feature = "disable-grow-in-place",
feature = "disable-realloc-in-place"
)))]
#[track_caller]
unsafe fn realloc(&self, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
let mut talc = self.as_talc();
// SAFETY: guaranteed by caller that `ptr` was previously allocated by
// this allocator given the layout `old_layout`.
if talc.try_realloc_in_place(ptr, old_layout, new_size) {
return ptr;
}
// grow in-place failed, reallocate manually
// SAFETY: guaranteed by caller that `new_size` is a valid layout size
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
// SAFETY: guaranteed by caller that `new_size` is nonzero
let allocation = match talc.allocate(new_layout) {
Some(ptr) => ptr.as_ptr(),
None => return null_mut(),
};
// Shrink always succeeds, only growing the allocation might fail,
// so the `old_layout.size() < new_size` here, and thus we just copy
// all the old allocation bytes.
allocation.copy_from_nonoverlapping(ptr, old_layout.size());
talc.deallocate(ptr, old_layout);
allocation
}
#[cfg(all(
feature = "disable-grow-in-place",
not(feature = "disable-realloc-in-place")
))]
#[track_caller]
unsafe fn realloc(&self, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
// SAFETY: See `Self::borrow`'s safety docs
let mut talc = self.as_talc();
if new_size <= old_layout.size() {
// SAFETY: guaranteed by caller that `ptr` was previously allocated by
// this allocator given the layout `old_layout`.
talc.shrink(ptr, old_layout, new_size);
return ptr;
}
// grow in-place failed, reallocate manually
// SAFETY: guaranteed by caller that `new_size` is a valid layout size
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
// SAFETY: guaranteed by caller that `new_size` is nonzero
let Some(allocation) = talc.allocate(new_layout) else { return null_mut() };
// Shrink always succeeds, only growing the allocation might fail,
// so the `old_layout.size() < new_size` here, and thus we just copy
// all the old allocation bytes.
allocation.as_ptr().copy_from_nonoverlapping(ptr, old_layout.size());
talc.deallocate(ptr, old_layout);
allocation.as_ptr()
}
#[cfg(feature = "disable-realloc-in-place")]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
// SAFETY: the caller must ensure that the `new_size` does not overflow.
// `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
let new_layout =
unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
// SAFETY: the caller must ensure that `new_layout` is greater than zero.
let new_ptr = unsafe { self.alloc(new_layout) };
if !new_ptr.is_null() {
// SAFETY: the previously allocated block cannot overlap the newly allocated block.
// The safety contract for `dealloc` must be upheld by the caller.
unsafe {
core::ptr::copy_nonoverlapping(
ptr,
new_ptr,
core::cmp::min(layout.size(), new_size),
);
self.dealloc(ptr, layout);
}
}
new_ptr
}
}
};
}