Skip to content

Commit 0cfc7c4

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 0cfc7c4

File tree

1 file changed

+77
-34
lines changed

1 file changed

+77
-34
lines changed

alloc-traits/src/ref_.rs

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,57 +4,65 @@ 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(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(alloc, layout)?;
5866
copy_nonoverlapping(
5967
alloc.ptr.as_ptr(),
6068
new_alloc.ptr.as_ptr(),
@@ -63,6 +71,29 @@ pub unsafe trait AllocRef {
6371
}
6472
}
6573

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

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)
127+
unsafe fn alloc_zeroed(&mut self, _: Allocation, layout: NonZeroLayout)
101128
-> Option<Allocation>
102129
{
103-
LocalAlloc::<'rf>::alloc_zeroed(*self, layout).map(Allocation::from_local)
130+
InitialAllocRef::alloc_zeroed(self, layout)
131+
}
132+
133+
unsafe fn dealloc(&mut self, alloc: Allocation) {
134+
LocalAlloc::<'rf>::dealloc(*self, alloc.into_local())
104135
}
105136

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

0 commit comments

Comments
 (0)