-
Notifications
You must be signed in to change notification settings - Fork 4
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
Make stashes generic over index types #3
Conversation
After thinking about this for a bit, I've decided not to merge as this adds a fair amount of complexity for little gain. Instead, I can guarantee that a stash will "pack" efficiently. This means that if you never insert more than If you disagree, feel free to discuss. |
So, this came up on #4 and I'm now interested in a simplified version. Specifically, would you be interested in modifying this to work with the following // We need this trait to allow panics when the index is out of range.
pub trait Index {
// Panics when `idx` is out of range.
fn from_usize(idx: usize) -> Self;
fn into_usize(self) -> usize;
}
// Auto implement this for types equivalent to `usize`.
impl<T> Index for T where T: From<usize> + Into<usize> {
fn from_usize(idx: usize) -> Self {
From::from(idx)
}
fn into_usize(self) -> usize {
Into::into(self)
}
} This should simplify this patch significantly. |
I might have a bit of time now yes. But I'm unclear on what implementation you have in mind... Because you say that the changes needed would be much less? I really don't see much difference from my proposed changes. The only difference with your trait is dropping the max() function and a few convenience methods. (which is fine with me, those methods could always be added to a newtype index wrapper if needed). |
The way I'm envisioning it, you'd convert to a usize at the beginning of the function and back to an I'd also hold off on the implementation for |
I have made changes that compiles without problem now. But I'm a bit stuck on the type inference not working in the tests and examples anymore. I've updated my fork with what I have so far. I will continue looking into what can be done about the current problem, but if you have any advice it would be welcome! And any other comments of course.... |
I found this post to be informative: http://stackoverflow.com/questions/37748306/default-generic-type-parameter-cannot-be-inferred
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, just a few nits.
src/stash/mod.rs
Outdated
inner: iter::Enumerate<slice::Iter<'a, Entry<V>>>, | ||
len: usize, | ||
_marker: marker::PhantomData<Ix>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, this should be marker::PhantomData<fn() -> Ix>
to indicate that we don't actually store any Ix
s although I'm not sure if it makes any difference...
src/stash/mod.rs
Outdated
data: Vec<Entry<V>>, | ||
size: usize, | ||
next_free: usize, | ||
// add a phantom user of the Ix type to make sure an instance of Stash is bound to one | ||
// specific index type, separate calls to put and get can't use different index types. | ||
_marker: marker::PhantomData<Ix>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shoudl probably be marker::PhantomData<fn(Ix) -> Ix>
.
src/stash/mod.rs
Outdated
@@ -268,7 +279,7 @@ impl<V> Stash<V> { | |||
/// | |||
/// *Panics* if the size of the `Stash<V>` would overflow `usize::MAX`. | |||
#[inline] | |||
pub fn put(&mut self, value: V) -> usize { | |||
pub fn put(&mut self, value: V) -> Ix { | |||
let loc = self.next_free; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to create the index here (to panic early if necessary): let idx = Ix::from_usize(self.next_free)
src/index.rs
Outdated
@@ -0,0 +1,18 @@ | |||
// We need this trait to allow panics when the index is out of range. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be documented (even if it's just a short "this is the index trait (auto implemented by usize)...").
That's... annoying. However, I'd still like this feature.
I'm not a fan of 3 and 4. I'm considering a variant of 2 where |
Adds the Index trait and makes Stash generic over any type that implements that trait. It still stores and works with usize internally, only convert indices at the API surface. The Stash::new() method is the only method that is not made generic over the index type used, it constructs a Stash with usize indices. It was done that way to keep examples and simple usages minimal, without need for type annotations, same as before this patch.
Ok, I've updated the commit according to your comments and also changed the new() method to only be available for creating Stash with usize index. For creating Stashes with other index types the default() method can be used. This is what petgraph is doing. I also did some minor updates to documentation comments. I'm pretty happy about how it looks now. Confirmed no regression on the benchmarks also. |
Thanks. To avoid breaking changes, how do you feel about treating let mut stash: Stash<T, usize> = Stash::default();
stash.reserve(capacity); |
Meaning that it will create a Stash that uses usize as index type. In the general case where a custom index type might be needed the user can construct the Stash with Stash::default() and then call reserve() to allocate needed capacity. This way we don't break existing code and the new use case of custom index types is still possible (and also pretty convenient.. not bad.) Also add a new example to show how a custom index type can be constructed and used.
Awesome! Thanks! |
Inspired by the petgraph library. The reason for a user to choose an index type smaller than usize is probably not to make Entry smaller, since most likely the V type is bigger anyway. The reason is for when storing lots of indices somewhere else, like when building graphs on top of stash. In that case the graph can end up storing lots of indices, so that size may actually matter.
So, one option could have been to keep the next_free field as an usize. I chose not to do that, thinking why not go all the way.
No testing done except from seeing that it compiles on rust 1.13.