Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for custom allocators in standard collections #42774
Comments
alexcrichton
added
B-unstable
T-libs
labels
Jun 20, 2017
This comment has been minimized.
This comment has been minimized.
|
There are some very interesting issues here:
|
This comment has been minimized.
This comment has been minimized.
I believe that the current design doesn't allow you to parametrize the error, so it must return the concrete error type with two arms - |
This comment has been minimized.
This comment has been minimized.
|
@joshlf err yes, this is predicated on us adding an associated error type. |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 11, 2017
|
To support the allocator trait in the collection types, the constructors will need to be duplicated. impl RawVec<T, A>
fn with_capacity(n: usize) -> RawVec<T, HeapAlloc>;
fn with_capacity_in(n: usize, a: A) -> RawVec<T, A>;
}I personally quite like this approach. |
alexcrichton
referenced this issue
Jul 12, 2017
Closed
Consider reverting the merge of collections into alloc #43112
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 14, 2017
|
@Ericson2314 mentioned this:
I am currently implementing a non-trivial allocator myself (for a relocatable heap) and noticed that it don't need to keep anything around for deallocation (the type information is still needed). This still works when multible allocators are used. I wonder if this could be integrated somehow? Associated types to indicate what needs to be stored? |
This comment has been minimized.
This comment has been minimized.
|
@s3bk
So the idea is that, for allocators where all instances of the type refer to the same global singleton, you wouldn't actually need to store a reference? Presumably that wouldn't work for allocators that could actually have multiple distinct instances, right? This motivates a follow-up: if you were implementing a global singleton, couldn't you just make the actual |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 15, 2017
Yes, for allocators with multiple instances the allocation function would benefit from non-zero knowledge. |
This comment has been minimized.
This comment has been minimized.
|
@s3bk How common is the case where you will only ever need to deallocate? All the standard collections and smart pointers have methods that allocate new memory from the same allocator (usually Hm, now that I think about it, those methods already need to clone the allocator, so that would potentially offer a way out. Although it's unclear to me if we can switch between storing |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 15, 2017
•
|
@rkruppe there could be trait Alloc {
type DeallocInfo;
fn dealloc(&self, ptr: *mut T, layout: Layout);
fn dealloc_with(info: Self::DeallocInfo, ptr: *mut T, layout: Layout);
// snip
}
struct Rc<T, A: Alloc> {
dealloc: A::DeallocInfo;
// snip
}
impl<T> Rc<T, HeapAlloc> {
fn make_mut(&mut self) -> &mut T {
// use HeapAlloc to potentially clone T
}
}
impl<T, A: Alloc> Rc<T, A> {
fn make_mut_in(&mut self, a: A) -> &mut T {
// use A to potentially clone T
}
}This would keep Rc as thin as possible, not break existing code and allow to use
|
This comment has been minimized.
This comment has been minimized.
|
@s3bk
|
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 15, 2017
|
@rkruppe It looks like I was completely wrong here. Most cases are covered by Box and the others reallocate. |
This comment has been minimized.
This comment has been minimized.
|
@s3bk
Is that a problem? The key property of |
This comment has been minimized.
This comment has been minimized.
|
@s3bk There's another angle to consider here: how do we obtain a |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 22, 2017
|
@joshlf The lifetime problem is indeed tricky… What if a lifetime would be added to the Alloc trait? trait Alloc<'a> {
type DeallocInfo;
fn dealloc_info(&self) -> Self::DeallocInfo;
...
}
impl<'a> Alloc<'a> for &'a MyAllocator {
type DeallocInfo = MyDeallocInfo<'a>;
…
} |
Mark-Simulacrum
added
the
C-tracking-issue
label
Jul 22, 2017
This comment has been minimized.
This comment has been minimized.
|
@s3bk that's an interesting approach, but doesn't doing |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Jul 22, 2017
|
@joshlf this crude example should not be Send or Sync. So it could safely be non-theadsafe . |
This comment has been minimized.
This comment has been minimized.
|
@s3bk Ah I think you're right about that. Good call. |
This comment has been minimized.
This comment has been minimized.
|
Not quite sure where the conversation is now, but we should probably discuss type SomeCollection<T> = collections::SomeCollection<T, GlobalAlloc>;As a temporary way to get the ball rolling here without impacting breaking std, needing newtypes or language design work for default params with aliases. (Picking up the discussion from #43112 (comment).) |
This comment has been minimized.
This comment has been minimized.
|
Cross post #32838 (comment) I've started generalizing the collections myself; the easiest way to demonstrate how the associated return type helps is to just do the code change, I suppose. |
matthewjasper
referenced this issue
Apr 3, 2018
Open
Custom global allocators (RFC 1398, RFC 1974) #287
This comment has been minimized.
This comment has been minimized.
|
So, as far as I can tell, the real issue here is the one with knowing which allocator to use for further allocations or deallocation using a type. In the case of a single instance of each This would seem to achieve the best of both worlds – no additional cost whatsoever over the current situation when you use the global allocator, and the necessary (but minimum) cost when you use custom allocators. |
This comment has been minimized.
This comment has been minimized.
|
@alexreg I don’t think there is a need for an What happens at the moment for |
This comment has been minimized.
This comment has been minimized.
|
@alexreg I guess I was waiting for some concensus that we would explore this path before working in it further. It wasn't very hard to get that far but these things bit-rot fast. See rust-lang-nursery/portability-wg#1 (comment) for where I propose this as part of a roadmap. |
This comment has been minimized.
This comment has been minimized.
|
I guess now that there is a global Alloc trait, this takes some of the pressure of regular Alloc. That might help things. |
This comment has been minimized.
This comment has been minimized.
|
@Ericson2314 I think there's an implicit go-ahead from people in the lang team, though I could be wrong. Certainly @glandium encouraged me submit a PR for this sort of stuff. Anyway, this doesn't need to be part of the portability / embedded development roadmap, though I can certainly see why it fits there. But with the interface for |
This comment has been minimized.
This comment has been minimized.
|
Note that I have boxed.rs changes for One thing that I would like to figure out is recursive use. Like, |
This comment has been minimized.
This comment has been minimized.
|
@glandium Good to know about Any optimisation for recursive usage of values that depend on custom allocators would be tricky, I think... Perhaps the way to go would be for all types supporting a custom allocator to implement a common trait that allows cloning while removing the allocator. Then it would be up to the collection/container to manage deallocation of items correctly using the reference to its own allocator. I reckon this would work without too many hitches, and would probably be an immediate improvement, but I worry about situations like this: let foo = Vec::new_in(alloc);
foo.push(Box::new_in(123, alloc));If the |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
What associated type? |
This comment has been minimized.
This comment has been minimized.
main--
commented
May 4, 2018
•
Note that this is not necessarily true: When an allocator is not zero-sized, this means that it carries some kind of contextual information to distinguish between multiple instances of it (most commonly a pointer to some manage information, e.g. for an arena). Considering that not only the The |
This comment has been minimized.
This comment has been minimized.
Yes, implementing Also, do you have any thoughts on my suggestion, @glandium? |
This comment has been minimized.
This comment has been minimized.
|
@glandium QuiltOS@0d29c18 It's crucial to how I share code between infallible and fallible stuff. |
This comment has been minimized.
This comment has been minimized.
main--
commented
May 4, 2018
|
@alexreg I don't see a solution for returning references to objects that had their allocator stripped in your proposal. Of course, the entire thing also falls flat on its face the moment you wrap a heap-allocated type into something else before storing it in the |
This comment has been minimized.
This comment has been minimized.
|
@Ericson2314: I have a proposal for fallible allocations (and a replacement for *_excess too) that I'll write up and post either as a pre-RFC or a RFC next week. |
This comment has been minimized.
This comment has been minimized.
|
@main-- For references, I was imagining that any containers/collections would only return "augmented references" (with a reference to the allocator, at least if it's not single-instance) – these would have As for the second issue, this would best be solved by making |
This comment has been minimized.
This comment has been minimized.
|
@glandium good look; hope what I linked is useful. Vec<Box<T, &SomeAlloc>, &SomeAlloc>I've been thinking (albeit just occasionally) about this for years, and the only solution I know of is linear types. I wouldn't worry about it for now. |
This comment has been minimized.
This comment has been minimized.
|
@Ericson2314 Any progress lately? Also, thoughts on the above regarding nested containers? |
This comment has been minimized.
This comment has been minimized.
|
I wrote up a proposal of a general-purpose execution context that might solve the problems with having to store |
Ericson2314
referenced this issue
Jun 29, 2018
Closed
A pure `alloc` library, with today's `alloc` becoming `global_alloc` #20
This comment has been minimized.
This comment has been minimized.
|
Here's a few PRs on this. Thanks @glandium! Compiler
Library |
This comment has been minimized.
This comment has been minimized.
|
The current API of It returns a Note that this means that an implementation of So how do we fix this. Well, first I thought about passing a size range, that is, a desired size, and a larger size, so that if the allocation cannot be shrunk in place to be in that range, we can error. But this is too complicated: Also, while the API of At this point, I think I would just prefer a EDIT: we could also make this method return a
Most ABIs support returning at least two scalar values in registers, so depending on how many registers it takes to return |
Ericson2314
referenced this issue
Jul 16, 2018
Closed
WIP: Allocator- and fallibility-polymorphic collections #52420
This comment has been minimized.
This comment has been minimized.
|
I just rebased my old branch making a WIP PR #52420 for this. |
Ericson2314
referenced this issue
Aug 2, 2018
Open
Tracking issue for RFC #2116: fallible collection allocation #48043
This comment has been minimized.
This comment has been minimized.
|
Hello! I've been working on a bump allocator and my use cases have required me to fork a couple (and eventually I'll probably end up forking more) Collections I have ported thus far:
General notes:
I hope these notes are helpful in some small way! |
This comment has been minimized.
This comment has been minimized.
|
Regarding Regarding Even if "deallocation" of the memory directly owned by |
This comment has been minimized.
This comment has been minimized.
|
Yes that is what I did for |
This comment has been minimized.
This comment has been minimized.
|
@fitzgen See the |
This comment has been minimized.
This comment has been minimized.
I think this signature would work with Rust today (although I have not tried it yet): impl<T, A: Alloc> Box<T, A> {
pub fn leak<'a>(self) -> &'a T
where
A: 'a,
{ ... }
} |
This comment has been minimized.
This comment has been minimized.
Filed fitzgen/bumpalo#2 |
alexcrichton commentedJun 20, 2017
The new
Alloctrait defined in RFC 1398 was added in #42313 but the libs teamdecided to hold off onVecintegration just yet to be conservative.This issue is intended to track the integration of the
Alloctrait into standard collections likeVec,BTreeMap, etc. I'm not personally aware of any current blockers, but what we'll probably want to do as part of this issue includes: