Skip to content
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

Multiple calls to vacant_entry / self referential entries. #55

Open
jpittis opened this issue Oct 14, 2018 · 5 comments
Open

Multiple calls to vacant_entry / self referential entries. #55

jpittis opened this issue Oct 14, 2018 · 5 comments

Comments

@jpittis
Copy link

jpittis commented Oct 14, 2018

TLDR: I want to be able to allocate multiple entries of a slab in a single go so I can have the entries reference each other.

Imagine you want to keep a value and a reference to another slab entry inside a slab.

Slab<(SomeValue, usize)>

So your the instance of your slab might contain something along the lines of this:

// slab[0] = (MyFirstValue, 1)
// slab[1] = (MySecondValue, 0)

There's currently no way to create two referencing entries inside a slab because we can't make multiple calls to vacant_entry.

let first_entry = slab.vacant_entry();
let second_entry = slab.vacant_entry();
// use the entry.key() from each vacant_entry to insert references to the other.

The only way for me to accomplish something like this right now is to update the entries using get_mut with the correct keys once I've already inserted the values.

Is this too a complex a feature request for this library?
Is there another, better way to do this?

@jpittis jpittis changed the title Multiple calls to vacant_entry / referential entries. Multiple calls to vacant_entry / self referential entries. Oct 14, 2018
@carllerche
Copy link
Member

The only way to do this safely would be to have a way to get N vacant entries atomically.

@tormol
Copy link
Contributor

tormol commented Mar 3, 2019

This could be implemented without allocating for the N entries by having an iterator that produce the keys that future insert()s will use. It wouldn't be completely foolproof as removing an element would invalidate the returned keys, but it doesn't require unsafe either.

It could be used as

let (first, second) = {
    let mut keys = slab.next_keys();
    (keys.next().unwrap(), keys.next().unwrap())
};
slab.insert(second);
slab.insert(first);

or

let keys = slab.next_keys().take(4).collect::<Vec<usize>>();
for key in keys {
    // ...
}

I've implemented this here and can open a pull request if anybody is interested.

@carllerche
Copy link
Member

@tormol Interesting thought.

I'm a little uncomfortable with that strategy as can issue other operations on the slab that would invalidate the promised keys. For example, if you remove an entry before using a promised key, that changes things.

@tormol
Copy link
Contributor

tormol commented Mar 5, 2019

Yes, after removing something then one will always get the wrong key, so any bug, if not immediately discovered, will at least be easy to reproduce.
I could add an example showing what happens if it's used wrong.

@carllerche
Copy link
Member

carllerche commented Mar 7, 2019

In general, I prefer opting for APIs that are hard (impossible) to misuse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants