Skip to content

Commit b449df9

Browse files
committed
Consider the allocator stored in an allocation
Avoiding the pointer to the allocator in every structure that contains a non-global allocator is possible by storing the pointer inside scratch space of existing allocations. However, that requires being passed one.
1 parent 8e0c15d commit b449df9

File tree

1 file changed

+78
-34
lines changed

1 file changed

+78
-34
lines changed

alloc-traits/src/ref_.rs

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,97 @@ use crate::NonZeroLayout;
44
use crate::LocalAlloc;
55

66
/// An allocation without tracked lifetime.
7+
#[derive(Copy, Clone)]
78
pub struct Allocation {
89
ptr: NonNull<u8>,
910
layout: NonZeroLayout,
1011
}
1112

1213
/// A references to an allocator.
1314
///
14-
/// Allocations must be live for the lifetime of `self`. That is one must be able to move the
15-
/// `self` and keep all allocations. In particular, a reference to a [`LocalAlloc`] is an
16-
/// `AllocRef`.
15+
/// Allocations created from this instance are valid for the lifetime of `self`. That is one must
16+
/// be able to move the `self` and all allocations remain valid. In particular, a reference to a
17+
/// [`LocalAlloc`] is an `AllocRef` as it is an immutable pin.
18+
///
19+
/// An allocation is said to be live when it is valid and has not been passed to `dealloc` and has
20+
/// not been passed to `realloc` that returned `Some(_)`.
21+
///
22+
/// Note that all methods require being passed some existing allocation, even if they do not
23+
/// consume it. See `InitialAllocRef` for those that do not.
1724
///
1825
/// [`LocalAlloc`]: trait.LocalAlloc.html
1926
pub unsafe trait AllocRef {
2027
/// Allocate one block of memory.
2128
///
22-
/// The callee guarantees that a successful return contains a pointer that is valid for **at
23-
/// least** the layout requested by the caller.
24-
fn alloc(&mut self, layout: NonZeroLayout) -> Option<Allocation>;
25-
26-
/// Deallocate a block previously allocated.
27-
/// # Safety
28-
/// The caller must ensure that:
29-
/// * `alloc` has been previously returned from a call to `alloc`.
30-
/// * There are no more pointer to the allocation.
31-
unsafe fn dealloc(&mut self, alloc: Allocation);
29+
/// The `existing` allocation can be used by the `AllocRef` to uniquely identify the allocator
30+
/// that is used internaly. It must be valid for the same `AllocRef`.
31+
///
32+
/// The callee guarantees that a successful return contains a pointer that fits the layout
33+
/// requested by the caller and the layout in the struct is the same as requested.
34+
unsafe fn alloc_from(&mut self, existing: Allocation, layout: NonZeroLayout) -> Option<Allocation>;
3235

3336
/// Allocate a block of memory initialized with zeros.
3437
///
35-
/// The callee guarantees that a successful return contains a pointer that is valid for **at
36-
/// least** the layout requested by the caller and the contiguous region of bytes, starting at
37-
/// the pointer and with the size of the returned layout, is initialized and zeroed.
38-
fn alloc_zeroed(&mut self, layout: NonZeroLayout)
38+
/// The callee guarantees that a successful return contains a pointer that fits the layout
39+
/// requested by the caller and the layout in the struct is the same as requested.
40+
unsafe fn alloc_zeroed_from(&mut self, existing: Allocation, layout: NonZeroLayout)
3941
-> Option<Allocation>
4042
{
41-
let allocation = self.alloc(layout)?;
42-
unsafe {
43-
write_bytes(allocation.ptr.as_ptr(), 0u8, allocation.layout.size().into());
44-
}
43+
let allocation = self.alloc_from(existing, layout)?;
44+
write_bytes(allocation.ptr.as_ptr(), 0u8, allocation.layout.size().into());
4545
Some(allocation)
4646
}
4747

48+
/// Deallocate a block previously allocated.
49+
/// # Safety
50+
/// The caller must ensure that:
51+
/// * `alloc` has been previously returned from a call to `alloc`.
52+
/// * There are no more pointer to the allocation.
53+
unsafe fn dealloc(&mut self, alloc: Allocation);
54+
4855
/// Change the layout of a block previously allocated.
4956
///
50-
/// The callee guarantees that a successful return contains a pointer that is valid for **at
51-
/// least** the layout requested by the caller and the contiguous region of bytes, starting at
52-
/// the pointer and with the size of the returned layout, is initialized with the prefix of the
53-
/// previous allocation that is still valid.
57+
/// The callee guarantees that a successful return contains a pointer that it fits the layout
58+
/// requested by the caller and the contiguous region of bytes, starting at the pointer and
59+
/// with the size of the returned layout, is initialized with the prefix of the previous
60+
/// allocation that is still valid, and that the layout in the returned struct is the same as
61+
/// requested.
5462
unsafe fn realloc(&mut self, alloc: Allocation, layout: NonZeroLayout)
5563
-> Option<Allocation>
5664
{
57-
let new_alloc = self.alloc(layout)?;
65+
let new_alloc = self.alloc_from(alloc, layout)?;
5866
copy_nonoverlapping(
5967
alloc.ptr.as_ptr(),
6068
new_alloc.ptr.as_ptr(),
6169
layout.size().min(alloc.layout.size()).into());
70+
self.dealloc(alloc);
6271
Some(new_alloc)
6372
}
6473
}
6574

75+
/// A trait for an `AllocRef` that requires no existing allocation to allocate.
76+
pub unsafe trait InitialAllocRef: AllocRef {
77+
/// Allocate one block of memory.
78+
///
79+
/// The callee guarantees that a successful return contains a pointer that fits the layout
80+
/// requested by the caller and the layout in the struct is the same as requested.
81+
fn alloc(&mut self, layout: NonZeroLayout) -> Option<Allocation>;
82+
83+
/// Allocate a block of memory initialized with zeros.
84+
///
85+
/// The callee guarantees that a successful return contains a pointer that fits the layout
86+
/// requested by the caller and the layout in the struct is the same as requested.
87+
fn alloc_zeroed(&mut self, layout: NonZeroLayout)
88+
-> Option<Allocation>
89+
{
90+
let allocation = InitialAllocRef::alloc(self, layout)?;
91+
unsafe {
92+
write_bytes(allocation.ptr.as_ptr(), 0u8, allocation.layout.size().into());
93+
}
94+
Some(allocation)
95+
}
96+
}
97+
6698
impl Allocation {
6799
pub(crate) fn from_local(alloc: crate::local::Allocation) -> Self {
68100
Allocation {
@@ -89,18 +121,18 @@ impl Allocation {
89121
unsafe impl<'rf, T> AllocRef for &'rf T
90122
where T: LocalAlloc<'rf>
91123
{
92-
fn alloc(&mut self, layout: NonZeroLayout) -> Option<Allocation> {
93-
LocalAlloc::<'rf>::alloc(*self, layout).map(Allocation::from_local)
124+
unsafe fn alloc_from(&mut self, _: Allocation, layout: NonZeroLayout) -> Option<Allocation> {
125+
InitialAllocRef::alloc(self, layout)
94126
}
95127

96-
unsafe fn dealloc(&mut self, alloc: Allocation) {
97-
LocalAlloc::<'rf>::dealloc(*self, alloc.into_local())
98-
}
99-
100-
fn alloc_zeroed(&mut self, layout: NonZeroLayout)
128+
unsafe fn alloc_zeroed_from(&mut self, _: Allocation, layout: NonZeroLayout)
101129
-> Option<Allocation>
102130
{
103-
LocalAlloc::<'rf>::alloc_zeroed(*self, layout).map(Allocation::from_local)
131+
InitialAllocRef::alloc_zeroed(self, layout)
132+
}
133+
134+
unsafe fn dealloc(&mut self, alloc: Allocation) {
135+
LocalAlloc::<'rf>::dealloc(*self, alloc.into_local())
104136
}
105137

106138
unsafe fn realloc(&mut self, alloc: Allocation, layout: NonZeroLayout)
@@ -110,3 +142,15 @@ unsafe impl<'rf, T> AllocRef for &'rf T
110142
.map(Allocation::from_local)
111143
}
112144
}
145+
146+
unsafe impl<'rf, T> InitialAllocRef for &'rf T
147+
where T: LocalAlloc<'rf>
148+
{
149+
fn alloc(&mut self, layout: NonZeroLayout) -> Option<Allocation> {
150+
LocalAlloc::<'rf>::alloc(*self, layout).map(Allocation::from_local)
151+
}
152+
153+
fn alloc_zeroed(&mut self, layout: NonZeroLayout) -> Option<Allocation> {
154+
LocalAlloc::<'rf>::alloc_zeroed(*self, layout).map(Allocation::from_local)
155+
}
156+
}

0 commit comments

Comments
 (0)