-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allocator API taking context #138
Comments
There are other uses for this context parameter. For instance, here is an arena allocator that uses lifetime tagging to prevent increasing the size of containers: // Cell<T> is invariant in T; so Cell<&'id _> makes `id` invariant.
// This means that the inference engine is not allowed to shrink or
// grow 'id to solve the borrow system.
type Id<'id> = PhantomData<::std::cell::Cell<&'id mut ()>>;
#[derive(Clone, Copy)]
pub struct Child<'id, 'p> {
_id: Id<'id>,
_parent: PhantomData<&'p Parent>,
}
pub struct Parent {
mem: Bump,
}
impl Parent {
pub fn new() -> Self {
Self {
mem: Bump::new()
}
}
}
#[derive(Clone, Copy)]
pub struct Context<'id, 'p> {
_id: Id<'id>,
parent: &'p Parent,
}
unsafe impl Allocator for Parent {
type Ctx = ();
fn allocate(&self, _context: (), layout: std::alloc::Layout) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
match self.mem.try_alloc_layout(layout) {
Ok(ptr) => Ok(NonNull::slice_from_raw_parts(ptr, layout.size())),
Err(_) => Err(AllocError),
}
}
unsafe fn deallocate(&self, _ptr: std::ptr::NonNull<u8>, _layout: std::alloc::Layout) {
// Deallocation handled by drop of `Parent`
}
}
unsafe impl<'id, 'p> Allocator for Child<'id, 'p> {
type Ctx = Context<'id, 'p>;
fn allocate(&self, context: Context<'id, 'p>, layout: std::alloc::Layout) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
context.parent.allocate((), layout)
}
unsafe fn deallocate(&self, _ptr: std::ptr::NonNull<u8>, _layout: std::alloc::Layout) {
// Deallocation handled by drop of `Parent`
}
}
impl Parent {
pub fn scope<'p, F>(&'p self, f: F)
where
F: for<'id> FnOnce(Child<'id, 'p>, Context<'id, 'p>)
{
let child = Child { _id: PhantomData, _parent: PhantomData };
let context = Context { _id: PhantomData, parent: self };
f(child, context)
}
} Usage: let arena = qalloc::Parent::new();
arena.scope(|child, context| {
let mut v = Vec::new_in(child);
v.cpush(123, context);
let arena2 = qalloc::Parent::new();
arena2.scope(|child2, context2| {
v.cpush(456, context);
let mut v2 = Vec::new_in(child2);
v2.cpush("abc", context2);
// v2.push("def", context); // Wrong context -> lifetime error
// v.push(789, context2); // Wrong context -> lifetime error
});
let mut v3 = Vec::new_in(Global);
// This box is only one pointer wide, since `Child` is a ZST
// So `v3` uses less heap memory
v3.push(Box::cnew_in("derp", child, context));
}); |
7 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The rust-for-linux project have their own allocator API including a custom allocator trait. I'm working on some modifications to the
Allocator
trait that would enable their use-cases. Essentially, what they need is a way to pass some flags at each (possible) allocation. For instance:Context as associated type on
Allocator
Add an associated type for additional context passed into (re)allocating functions.
Then for each heap container, we would have a copy of each (re)allocating function that takes a generic context:
rust-for-linux folks would have to use
cpush
Could even use
#![feature(default_associated_types)]
to makeCtx
default to()
. Though since the allocator API is unstable, this isn't necessary.Variant:
Ctx
as a trait genericYou could make
Ctx
a type parameter of the trait instead:But I fail to see a case where an allocator would want to support multiple types of context.
This would also require that every heap type wanting to generically support allocators taking context would need to add a
PhantomData<Ctx>
to their struct.Questions
Ctx
be passed by reference?Then we could remove the
Copy
bound, but people could also just setCtx = &Something
.Problems
push
,reserve
, etc would all need to be duplicated with a context-taking variantThe only way to avoid this is some new language feature, such as making final
()
arguments optional or calculating disjointness based on associated types.Extend
, etc can only be implemented for containers whereCtx = ()
This could possibly be mitigated by providing ways to bundle or split up the allocator and context, for instance:
The text was updated successfully, but these errors were encountered: